mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-19 08:15:08 +00:00
If you run ./byfn -m up prior to running ./byfn -m generate, things will fail - which would normally be OK except in the case where you are running the Docker daemon as root - which is the default on Linux systems. The issue is that the Docker daemon will automatically generate host paths for volumes if they don't exist and they will be owned by whoever is running the Docker process resulting in the error reported in FAB-5038. To fix this, simply check for the existence of the crypto-config folder and if it does not exist run the equivalent commands as the generate option Change-Id: Ic5b48682a527951ac6eab5b5cf2d0fc6dbdaad56 Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
349 lines
13 KiB
Bash
Executable file
349 lines
13 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# This script will orchestrate a sample end-to-end execution of the Hyperledger
|
|
# Fabric network.
|
|
#
|
|
# The end-to-end verification provisions a sample Fabric network consisting of
|
|
# two organizations, each maintaining two peers, and a “solo” ordering service.
|
|
#
|
|
# This verification makes use of two fundamental tools, which are necessary to
|
|
# create a functioning transactional network with digital signature validation
|
|
# and access control:
|
|
#
|
|
# * cryptogen - generates the x509 certificates used to identify and
|
|
# authenticate the various components in the network.
|
|
# * configtxgen - generates the requisite configuration artifacts for orderer
|
|
# bootstrap and channel creation.
|
|
#
|
|
# Each tool consumes a configuration yaml file, within which we specify the topology
|
|
# of our network (cryptogen) and the location of our certificates for various
|
|
# configuration operations (configtxgen). Once the tools have been successfully run,
|
|
# we are able to launch our network. More detail on the tools and the structure of
|
|
# the network will be provided later in this document. For now, let's get going...
|
|
|
|
# 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:${PWD}:$PATH
|
|
export FABRIC_CFG_PATH=${PWD}
|
|
|
|
# Print the usage message
|
|
function printHelp () {
|
|
echo "Usage: "
|
|
echo " byfn.sh -m up|down|restart|generate [-c <channel name>] [-t <timeout>]"
|
|
echo " byfn.sh -h|--help (print this message)"
|
|
echo " -m <mode> - one of 'up', 'down', 'restart' or 'generate'"
|
|
echo " - 'up' - bring up the network with docker-compose up"
|
|
echo " - 'down' - bring up the network with docker-compose up"
|
|
echo " - 'restart' - bring up the network with docker-compose up"
|
|
echo " - 'generate' - generate required certificates and genesis block"
|
|
echo " -c <channel name> - channel name to use (defaults to \"mychannel\")"
|
|
echo " -t <timeout> - CLI timeout duration in microseconds (defaults to 10000)"
|
|
echo
|
|
echo "Typically, one would first generate the required certificates and "
|
|
echo "genesis block, then bring up the network. e.g.:"
|
|
echo
|
|
echo " byfn.sh -m generate -c <channelname>"
|
|
echo " byfn.sh -m up -c <channelname>"
|
|
echo " byfn.sh -m down -c <channelname>"
|
|
echo
|
|
echo "Taking all defaults:"
|
|
echo " byfn.sh -m generate"
|
|
echo " byfn.sh -m up"
|
|
echo " byfn.sh -m down"
|
|
}
|
|
|
|
# Ask user for confirmation to proceed
|
|
function askProceed () {
|
|
read -p "Continue (y/n)? " ans
|
|
case "$ans" in
|
|
y|Y )
|
|
echo "proceeding ..."
|
|
;;
|
|
n|N )
|
|
echo "exiting..."
|
|
exit 1
|
|
;;
|
|
* )
|
|
echo "invalid response"
|
|
askProceed
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Obtain CONTAINER_IDS and remove them
|
|
# TODO Might want to make this optional - could clear other containers
|
|
function clearContainers () {
|
|
CONTAINER_IDS=$(docker ps -aq)
|
|
if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then
|
|
echo "---- 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:
|
|
# TODO list generated image naming patterns
|
|
function removeUnwantedImages() {
|
|
DOCKER_IMAGE_IDS=$(docker images | grep "dev\|none\|test-vp\|peer[0-9]-" | awk '{print $3}')
|
|
if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then
|
|
echo "---- No images available for deletion ----"
|
|
else
|
|
docker rmi -f $DOCKER_IMAGE_IDS
|
|
fi
|
|
}
|
|
|
|
# Generate the needed certificates, the genesis block and start the network.
|
|
function networkUp () {
|
|
# generate artifacts if they don't exist
|
|
if [ ! -d "crypto-config" ]; then
|
|
generateCerts
|
|
replacePrivateKey
|
|
generateChannelArtifacts
|
|
fi
|
|
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT docker-compose -f $COMPOSE_FILE up -d 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "ERROR !!!! Unable to start network"
|
|
docker logs -f cli
|
|
exit 1
|
|
fi
|
|
docker logs -f cli
|
|
}
|
|
|
|
# Tear down running network
|
|
function networkDown () {
|
|
docker-compose -f $COMPOSE_FILE down
|
|
# Don't remove containers, images, etc if restarting
|
|
if [ "$MODE" != "restart" ]; then
|
|
#Cleanup the chaincode containers
|
|
clearContainers
|
|
#Cleanup images
|
|
removeUnwantedImages
|
|
# remove orderer block and other channel configuration transactions and certs
|
|
rm -rf channel-artifacts/*.block channel-artifacts/*.tx crypto-config
|
|
# remove the docker-compose yaml file that was customized to the example
|
|
rm -f docker-compose-e2e.yaml
|
|
fi
|
|
}
|
|
|
|
# Using docker-compose-e2e-template.yaml, replace constants with private key file names
|
|
# generated by the cryptogen tool and output a docker-compose.yaml specific to this
|
|
# configuration
|
|
function replacePrivateKey () {
|
|
# sed on MacOSX does not support -i flag with a null extension. We will use
|
|
# 't' for our back-up's extension and depete it at the end of the function
|
|
ARCH=`uname -s | grep Darwin`
|
|
if [ "$ARCH" == "Darwin" ]; then
|
|
OPTS="-it"
|
|
else
|
|
OPTS="-i"
|
|
fi
|
|
|
|
# Copy the template to the file that will be modified to add the private key
|
|
cp docker-compose-e2e-template.yaml docker-compose-e2e.yaml
|
|
|
|
# The next steps will replace the template's contents with the
|
|
# actual values of the private key file names for the two CAs.
|
|
CURRENT_DIR=$PWD
|
|
cd crypto-config/peerOrganizations/org1.example.com/ca/
|
|
PRIV_KEY=$(ls *_sk)
|
|
cd $CURRENT_DIR
|
|
sed $OPTS "s/CA1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
|
|
cd crypto-config/peerOrganizations/org2.example.com/ca/
|
|
PRIV_KEY=$(ls *_sk)
|
|
cd $CURRENT_DIR
|
|
sed $OPTS "s/CA2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
|
|
# If MacOSX, remove the temporary backup of the docker-compose file
|
|
if [ "$ARCH" == "Darwin" ]; then
|
|
rm docker-compose-e2e.yamlt
|
|
fi
|
|
}
|
|
|
|
# We will use the cryptogen tool to generate the cryptographic material (x509 certs)
|
|
# for our various network entities. The certificates are based on a standard PKI
|
|
# implementation where validation is achieved by reaching a common trust anchor.
|
|
#
|
|
# Cryptogen consumes a file - ``crypto-config.yaml`` - that contains the network
|
|
# topology and allows us to generate a library of certificates for both the
|
|
# Organizations and the components that belong to those Organizations. Each
|
|
# Organization is provisioned a unique root certificate (``ca-cert``), that binds
|
|
# specific components (peers and orderers) to that Org. Transactions and communications
|
|
# within Fabric are signed by an entity's private key (``keystore``), and then verified
|
|
# by means of a public key (``signcerts``). You will notice a "count" variable within
|
|
# this file. We use this to specify the number of peers per Organization; in our
|
|
# case it's two peers per Org. The rest of this template is extremely
|
|
# self-explanatory.
|
|
#
|
|
# After we run the tool, the certs will be parked in a folder titled ``crypto-config``.
|
|
|
|
# Generates Org certs using cryptogen tool
|
|
function generateCerts (){
|
|
which cryptogen
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "cryptogen tool not found. exiting"
|
|
exit 1
|
|
fi
|
|
echo
|
|
echo "##########################################################"
|
|
echo "##### Generate certificates using cryptogen tool #########"
|
|
echo "##########################################################"
|
|
|
|
cryptogen generate --config=./crypto-config.yaml
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate certificates..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
}
|
|
|
|
# The `configtxgen tool is used to create four artifacts: orderer **bootstrap
|
|
# block**, fabric **channel configuration transaction**, and two **anchor
|
|
# peer transactions** - one for each Peer Org.
|
|
#
|
|
# The orderer block is the genesis block for the ordering service, and the
|
|
# channel transaction file is broadcast to the orderer at channel creation
|
|
# time. The anchor peer transactions, as the name might suggest, specify each
|
|
# Org's anchor peer on this channel.
|
|
#
|
|
# Configtxgen consumes a file - ``configtx.yaml`` - that contains the definitions
|
|
# for the sample network. There are three members - one Orderer Org (``OrdererOrg``)
|
|
# and two Peer Orgs (``Org1`` & ``Org2``) each managing and maintaining two peer nodes.
|
|
# This file also specifies a consortium - ``SampleConsortium`` - consisting of our
|
|
# two Peer Orgs. Pay specific attention to the "Profiles" section at the top of
|
|
# this file. You will notice that we have two unique headers. One for the orderer genesis
|
|
# block - ``TwoOrgsOrdererGenesis`` - and one for our channel - ``TwoOrgsChannel``.
|
|
# These headers are important, as we will pass them in as arguments when we create
|
|
# our artifacts. This file also contains two additional specifications that are worth
|
|
# noting. Firstly, we specify the anchor peers for each Peer Org
|
|
# (``peer0.org1.example.com`` & ``peer0.org2.example.com``). Secondly, we point to
|
|
# the location of the MSP directory for each member, in turn allowing us to store the
|
|
# root certificates for each Org in the orderer genesis block. This is a critical
|
|
# concept. Now any network entity communicating with the ordering service can have
|
|
# its digital signature verified.
|
|
#
|
|
# This function will generate the crypto material and our four configuration
|
|
# artifacts, and subsequently output these files into the ``channel-artifacts``
|
|
# folder.
|
|
#
|
|
# 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.
|
|
|
|
# Generate orderer genesis block, channel configuration transaction and
|
|
# anchor peer update transactions
|
|
function generateChannelArtifacts() {
|
|
which configtxgen
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "configtxgen tool not found. exiting"
|
|
exit 1
|
|
fi
|
|
|
|
echo "##########################################################"
|
|
echo "######### Generating Orderer Genesis block ##############"
|
|
echo "##########################################################"
|
|
# Note: For some unknown reason (at least for now) the block file can't be
|
|
# named orderer.genesis.block or the orderer will fail to launch!
|
|
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate orderer genesis block..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
echo "#################################################################"
|
|
echo "### Generating channel configuration transaction 'channel.tx' ###"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate channel configuration transaction..."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "#################################################################"
|
|
echo "####### Generating anchor peer update for Org1MSP ##########"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate anchor peer update for Org1MSP..."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "#################################################################"
|
|
echo "####### Generating anchor peer update for Org2MSP ##########"
|
|
echo "#################################################################"
|
|
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate \
|
|
./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Failed to generate anchor peer update for Org2MSP..."
|
|
exit 1
|
|
fi
|
|
echo
|
|
}
|
|
|
|
# Obtain the OS and Architecture string that will be used to select the correct
|
|
# native binaries for your platform
|
|
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)}')
|
|
# timeout duration - the duration the CLI should wait for a response from
|
|
# another container before giving up
|
|
CLI_TIMEOUT=10000
|
|
# channel name defaults to "mychannel"
|
|
CHANNEL_NAME="mychannel"
|
|
# use this as the default docker-compose yaml definition
|
|
COMPOSE_FILE=docker-compose-cli.yaml
|
|
|
|
# Parse commandline args
|
|
while getopts "h?m:c:t:" opt; do
|
|
case "$opt" in
|
|
h|\?)
|
|
printHelp
|
|
exit 0
|
|
;;
|
|
m) MODE=$OPTARG
|
|
;;
|
|
c) CHANNEL_NAME=$OPTARG
|
|
;;
|
|
t) CLI_TIMEOUT=$OPTARG
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Determine whether starting, stopping, restarting or generating for announce
|
|
if [ "$MODE" == "up" ]; then
|
|
EXPMODE="Starting"
|
|
elif [ "$MODE" == "down" ]; then
|
|
EXPMODE="Stopping"
|
|
elif [ "$MODE" == "restart" ]; then
|
|
EXPMODE="Restarting"
|
|
elif [ "$MODE" == "generate" ]; then
|
|
EXPMODE="Generating certs and genesis block for"
|
|
else
|
|
printHelp
|
|
exit 1
|
|
fi
|
|
|
|
# Announce what was requested
|
|
echo "${EXPMODE} with channel '${CHANNEL_NAME}' and CLI timeout of '${CLI_TIMEOUT}'"
|
|
|
|
# ask for confirmation to proceed
|
|
askProceed
|
|
|
|
#Create the network using docker compose
|
|
if [ "${MODE}" == "up" ]; then
|
|
networkUp
|
|
elif [ "${MODE}" == "down" ]; then ## Clear the network
|
|
networkDown
|
|
elif [ "${MODE}" == "generate" ]; then ## Generate Artifacts
|
|
generateCerts
|
|
replacePrivateKey
|
|
generateChannelArtifacts
|
|
elif [ "${MODE}" == "restart" ]; then ## Restart the network
|
|
networkDown
|
|
networkUp
|
|
else
|
|
printHelp
|
|
exit 1
|
|
fi
|