#!/usr/bin/env bash set -v -eou pipefail # Log all commands set -x # All tests run in the workshop root folder cd "$(dirname "$0")"/.. # Clean house on exit function exitHook() { # Just in case the just left some bits running around kind delete cluster --name kind # Just in case ... if docker inspect kind-registry &>/dev/null; then echo "Stopping container registry" docker kill kind-registry docker rm kind-registry fi # Delete the sample network configuration and crypto material rm -rf "${WORKSHOP_PATH}"/_cfg } trap exitHook SIGINT SIGTERM EXIT ############################################################################### # 00-setup ############################################################################### export WORKSHOP_PATH="${PWD}" export PATH="${WORKSHOP_PATH}/bin:${PATH}" export FABRIC_CFG_PATH="${WORKSHOP_PATH}/config" "${WORKSHOP_PATH}/check.sh" kubectl version --client -o yaml kind version export LOG_ERROR_LINES=20 ############################################################################### # 10-kube ############################################################################### # env checks [[ ${WORKSHOP_PATH+x} ]] || exit 1 [[ ${FABRIC_CFG_PATH+x} ]] || exit 1 just check-setup # Set the ingress domain and target k8s namespace export WORKSHOP_INGRESS_DOMAIN=localho.st export WORKSHOP_NAMESPACE=test-network # Create a Kubernetes cluster in Docker, configure a Traefik ingress, and docker container registry just kind # KIND will set the current kube client context in ~/.kube/config kubectl cluster-info # Run k9s to observe the target namespace # k9s -n $WORKSHOP_NAMESPACE ############################################################################### # 20-fabric ############################################################################### # Clear out any certs from a prior run, just in case rm -rf ${WORKSHOP_PATH}/infrastructure/sample-network/temp just check-kube # env checks [[ ${WORKSHOP_PATH+x} ]] || exit 1 [[ ${FABRIC_CFG_PATH+x} ]] || exit 1 [[ ${WORKSHOP_INGRESS_DOMAIN+x} ]] || exit 1 [[ ${WORKSHOP_NAMESPACE+x} ]] || exit 1 # check Traefik ingress kubectl -n traefik get all kubectl -n traefik get deployment.apps/traefik curl http://${WORKSHOP_INGRESS_DOMAIN} # Install operator CRDs kubectl apply -k https://github.com/hyperledger-labs/fabric-operator.git/config/crd kubectl get customresourcedefinition.apiextensions.k8s.io/ibpcas.ibp.com kubectl get customresourcedefinition.apiextensions.k8s.io/ibpconsoles.ibp.com kubectl get customresourcedefinition.apiextensions.k8s.io/ibporderers.ibp.com kubectl get customresourcedefinition.apiextensions.k8s.io/ibppeers.ibp.com kubectl wait --for condition=established customresourcedefinition.apiextensions.k8s.io/ibpcas.ibp.com kubectl wait --for condition=established customresourcedefinition.apiextensions.k8s.io/ibpconsoles.ibp.com kubectl wait --for condition=established customresourcedefinition.apiextensions.k8s.io/ibporderers.ibp.com kubectl wait --for condition=established customresourcedefinition.apiextensions.k8s.io/ibppeers.ibp.com # Bring up the network just cloud-network # Operator running? kubectl -n ${WORKSHOP_NAMESPACE} get deployment fabric-operator # Did it apply the CRDs? kubectl -n ${WORKSHOP_NAMESPACE} get ibpca org0-ca kubectl -n ${WORKSHOP_NAMESPACE} get ibpca org1-ca kubectl -n ${WORKSHOP_NAMESPACE} get ibpca org2-ca kubectl -n ${WORKSHOP_NAMESPACE} get ibppeer org1-peer1 kubectl -n ${WORKSHOP_NAMESPACE} get ibppeer org1-peer2 kubectl -n ${WORKSHOP_NAMESPACE} get ibppeer org2-peer1 kubectl -n ${WORKSHOP_NAMESPACE} get ibppeer org2-peer2 kubectl -n ${WORKSHOP_NAMESPACE} get ibporderer org0-orderersnode1 kubectl -n ${WORKSHOP_NAMESPACE} get ibporderer org0-orderersnode2 kubectl -n ${WORKSHOP_NAMESPACE} get ibporderer org0-orderersnode3 # Did the operator reconcile the CRDs as deployments? kubectl -n ${WORKSHOP_NAMESPACE} get deployment fabric-operator kubectl -n ${WORKSHOP_NAMESPACE} get deployment org0-ca kubectl -n ${WORKSHOP_NAMESPACE} get deployment org0-orderersnode1 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org0-orderersnode2 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org0-orderersnode3 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org1-ca kubectl -n ${WORKSHOP_NAMESPACE} get deployment org1-peer1 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org1-peer2 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org2-ca kubectl -n ${WORKSHOP_NAMESPACE} get deployment org2-peer1 kubectl -n ${WORKSHOP_NAMESPACE} get deployment org2-peer2 export WORKSHOP_CRYPTO=$WORKSHOP_PATH/infrastructure/sample-network/temp # Hit the CAs using the TLS certs, etc. curl -s --cacert $WORKSHOP_CRYPTO/cas/org0-ca/tls-cert.pem https://$WORKSHOP_NAMESPACE-org0-ca-ca.$WORKSHOP_INGRESS_DOMAIN/cainfo | jq -c curl -s --cacert $WORKSHOP_CRYPTO/cas/org1-ca/tls-cert.pem https://$WORKSHOP_NAMESPACE-org1-ca-ca.$WORKSHOP_INGRESS_DOMAIN/cainfo | jq -c curl -s --cacert $WORKSHOP_CRYPTO/cas/org2-ca/tls-cert.pem https://$WORKSHOP_NAMESPACE-org2-ca-ca.$WORKSHOP_INGRESS_DOMAIN/cainfo | jq -c # create a channel just cloud-channel # enrollment certificates and channel MSP find ${WORKSHOP_CRYPTO} ############################################################################### # 30-chaincode ############################################################################### just check-network # env checks [[ ${FABRIC_CFG_PATH+x} ]] || exit 1 [[ ${WORKSHOP_PATH+x} ]] || exit 1 [[ ${WORKSHOP_CRYPTO+x} ]] || exit 1 [[ ${WORKSHOP_INGRESS_DOMAIN+x} ]] || exit 1 [[ ${WORKSHOP_NAMESPACE+x} ]] || exit 1 # org1-peer1 peer CLI context export ORG1_PEER1_ADDRESS=${WORKSHOP_NAMESPACE}-org1-peer1-peer.${WORKSHOP_INGRESS_DOMAIN}:443 export ORG1_PEER2_ADDRESS=${WORKSHOP_NAMESPACE}-org1-peer2-peer.${WORKSHOP_INGRESS_DOMAIN}:443 export CORE_PEER_LOCALMSPID=Org1MSP export CORE_PEER_ADDRESS=${ORG1_PEER1_ADDRESS} export CORE_PEER_TLS_ENABLED=true export CORE_PEER_MSPCONFIGPATH=${WORKSHOP_CRYPTO}/enrollments/org1/users/org1admin/msp export CORE_PEER_TLS_ROOTCERT_FILE=${WORKSHOP_CRYPTO}/channel-msp/peerOrganizations/org1/msp/tlscacerts/tlsca-signcert.pem export CORE_PEER_CLIENT_CONNTIMEOUT=15s export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s export ORDERER_ENDPOINT=${WORKSHOP_NAMESPACE}-org0-orderersnode1-orderer.${WORKSHOP_INGRESS_DOMAIN}:443 export ORDERER_TLS_CERT=${WORKSHOP_CRYPTO}/channel-msp/ordererOrganizations/org0/orderers/org0-orderersnode1/tls/signcerts/tls-cert.pem function build_cc() { CONTAINER_REGISTRY=$WORKSHOP_INGRESS_DOMAIN:5000 CHAINCODE_IMAGE=$CONTAINER_REGISTRY/$CHAINCODE_NAME # Build the chaincode image ARCH=$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g') docker build --build-arg TARGETARCH=${ARCH} -t $CHAINCODE_IMAGE contracts/$CHAINCODE_NAME-typescript # Push the image to the insecure container registry docker push $CHAINCODE_IMAGE } function prepare_cc() { IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' $CHAINCODE_IMAGE | cut -d'@' -f2) infrastructure/pkgcc.sh -l $CHAINCODE_NAME -n localhost:5000/$CHAINCODE_NAME -d $IMAGE_DIGEST } function install_cc() { CORE_PEER_ADDRESS=${ORG1_PEER1_ADDRESS} peer lifecycle chaincode install $CHAINCODE_PACKAGE CORE_PEER_ADDRESS=${ORG1_PEER2_ADDRESS} peer lifecycle chaincode install $CHAINCODE_PACKAGE export PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid $CHAINCODE_PACKAGE) && echo $PACKAGE_ID peer lifecycle \ chaincode approveformyorg \ --channelID ${CHANNEL_NAME} \ --name ${CHAINCODE_NAME} \ --version ${VERSION} \ --package-id ${PACKAGE_ID} \ --sequence ${SEQUENCE} \ --orderer ${ORDERER_ENDPOINT} \ --tls --cafile ${ORDERER_TLS_CERT} \ --connTimeout 15s peer lifecycle \ chaincode commit \ --channelID ${CHANNEL_NAME} \ --name ${CHAINCODE_NAME} \ --version ${VERSION} \ --sequence ${SEQUENCE} \ --orderer ${ORDERER_ENDPOINT} \ --tls --cafile ${ORDERER_TLS_CERT} \ --connTimeout 15s } function check_cc_meta() { peer chaincode query -n $CHAINCODE_NAME -C mychannel -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' | jq } ############################################################################### # 31 : build, tag, push, install ############################################################################### CHANNEL_NAME=mychannel VERSION=v0.0.1 SEQUENCE=1 CHAINCODE_NAME=asset-transfer CHAINCODE_PACKAGE=${CHAINCODE_NAME}.tgz build_cc prepare_cc install_cc check_cc_meta # cc pod is up - is there a selector for the target sequence / rev? kubectl -n test-network describe pods -l app.kubernetes.io/created-by=fabric-builder-k8s kubectl -n ${WORKSHOP_NAMESPACE} describe pods -l app.kubernetes.io/created-by=fabric-builder-k8s COUNT=$(kubectl -n ${WORKSHOP_NAMESPACE} get pods -l app.kubernetes.io/created-by=fabric-builder-k8s | wc -l) # one pod per peer + header line [[ $COUNT -eq 3 ]] ############################################################################### # 31 : build, tag, push, install ############################################################################### # build again and iterate SEQUENCE=$((SEQUENCE + 1)) VERSION=v0.0.$SEQUENCE build_cc prepare_cc install_cc check_cc_meta COUNT=$(kubectl -n ${WORKSHOP_NAMESPACE} get pods -l app.kubernetes.io/created-by=fabric-builder-k8s | wc -l) # one pod per peer + header line [[ $COUNT -eq 5 ]] ############################################################################### # 32 : Install chaincode from a prepared / CI package on a web server ############################################################################### SEQUENCE=$((SEQUENCE + 1)) VERSION=v0.1.3 CHAINCODE_PACKAGE=asset-transfer-typescript-${VERSION}.tgz # Download the package from a github release curl -LO https://github.com/hyperledgendary/full-stack-asset-transfer-guide/releases/download/${VERSION}/${CHAINCODE_PACKAGE} install_cc check_cc_meta COUNT=$(kubectl -n ${WORKSHOP_NAMESPACE} get pods -l app.kubernetes.io/created-by=fabric-builder-k8s | wc -l) # one pod per peer + header line [[ $COUNT -eq 7 ]] ############################################################################### # 33 : crazy time, run CCaaS on localhost, invoked by peer in k8s ############################################################################### echo "todo: 33 : crazy time, run CCaaS on localhost, invoked by peer in k8s" ############################################################################### # 40-bananas ############################################################################### # env checks [[ ${FABRIC_CFG_PATH+x} ]] || exit 1 [[ ${WORKSHOP_PATH+x} ]] || exit 1 [[ ${WORKSHOP_CRYPTO+x} ]] || exit 1 [[ ${WORKSHOP_INGRESS_DOMAIN+x} ]] || exit 1 [[ ${WORKSHOP_NAMESPACE+x} ]] || exit 1 # User organization MSP ID export MSP_ID=Org1MSP export ORG=org1 export USERNAME=org1user export PASSWORD=org1userpw # register / enroll the new user ADMIN_MSP_DIR=$WORKSHOP_CRYPTO/enrollments/${ORG}/users/rcaadmin/msp USER_MSP_DIR=$WORKSHOP_CRYPTO/enrollments/${ORG}/users/${USERNAME}/msp PEER_MSP_DIR=$WORKSHOP_CRYPTO/channel-msp/peerOrganizations/${ORG}/msp fabric-ca-client register \ --id.name $USERNAME \ --id.secret $PASSWORD \ --id.type client \ --url https://$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN \ --tls.certfiles $WORKSHOP_CRYPTO/cas/$ORG-ca/tls-cert.pem \ --mspdir $WORKSHOP_CRYPTO/enrollments/$ORG/users/rcaadmin/msp fabric-ca-client enroll \ --url https://$USERNAME:$PASSWORD@$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN \ --tls.certfiles $WORKSHOP_CRYPTO/cas/$ORG-ca/tls-cert.pem \ --mspdir $WORKSHOP_CRYPTO/enrollments/$ORG/users/$USERNAME/msp mv $USER_MSP_DIR/keystore/*_sk $USER_MSP_DIR/keystore/key.pem # Path to private key file export PRIVATE_KEY=${USER_MSP_DIR}/keystore/key.pem # Path to user certificate file export CERTIFICATE=${USER_MSP_DIR}/signcerts/cert.pem # Path to CA certificate export TLS_CERT=${PEER_MSP_DIR}/tlscacerts/tlsca-signcert.pem # Gateway peer SSL host name override export HOST_ALIAS=${WORKSHOP_NAMESPACE}-${ORG}-peer1-peer.${WORKSHOP_INGRESS_DOMAIN} # Gateway endpoint export ENDPOINT=$HOST_ALIAS:443 # Build the client application pushd applications/trader-typescript npm install npm start getAllAssets npm start create banana bananaman yellow npm start getAllAssets npm start transact npm start getAllAssets ##### Take it further: Gateway load balancing # Set up the k8s Ingress and Service kubectl kustomize \ ../../infrastructure/sample-network/config/gateway \ | envsubst \ | kubectl -n ${WORKSHOP_NAMESPACE} apply -f - # Try submitting a few transactions to the different peer endpoints unset HOST_ALIAS # Try a few times with org1-peer1 export ENDPOINT=${WORKSHOP_NAMESPACE}-org1-peer1-peer.${WORKSHOP_INGRESS_DOMAIN}:443 npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start getAllAssets # Then with org1-peer2 export ENDPOINT=${WORKSHOP_NAMESPACE}-org1-peer2-peer.${WORKSHOP_INGRESS_DOMAIN}:443 npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start getAllAssets # Then with the gateway endpoint. Connections will be distributed across org1-peer1 and org1-peer2 export ENDPOINT=${WORKSHOP_NAMESPACE}-org1-peer-gateway.${WORKSHOP_INGRESS_DOMAIN}:443 npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start transact npm start getAllAssets npm start getAllAssets npm start getAllAssets npm start getAllAssets popd ############################################################################### # 90-teardown ############################################################################### just cloud-network-down ############################################################################### # Looks good! ############################################################################### exit 0