# # Copyright contributors to the Hyperledgendary Full Stack Asset Transfer project # # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Main justfile to run all the development scripts # To install 'just' see https://github.com/casey/just#installation ############################################################################### # COMMON TARGETS # ############################################################################### # Ensure all properties are exported as shell env-vars set export # set the current directory, and the location of the test dats CWDIR := justfile_directory() _default: @just -f {{justfile()}} --list # Run the check script to validate tool versions installed check: ${CWDIR}/check.sh cluster_name := env_var_or_default("WORKSHOP_CLUSTER_NAME", "kind") cluster_runtime := env_var_or_default("WORKSHOP_CLUSTER_RUNTIME", "kind") ingress_domain := env_var_or_default("WORKSHOP_INGRESS_DOMAIN", "localho.st") storage_class := env_var_or_default("WORKSHOP_STORAGE_CLASS", "standard") chaincode_name := env_var_or_default("WORKSHOP_CHAINCODE_NAME", "asset-transfer") internal_repo_endpoint := env_var_or_default("WORKSHOP_INTERNAL_REPO", "localhost:5000") external_repo_endpoint := env_var_or_default("WORKSHOP_EXTERNAL_REPO", "localhost:5000") cluster_type := env_var_or_default("WORKSHOP_CLUSTER_TYPE", "k8s") # Start a local KIND cluster with nginx, localhost:5000 registry, and *.localho.st alias in kube DNS kind: unkind #!/usr/bin/env bash set -e -o pipefail infrastructure/kind_with_nginx.sh {{cluster_name}} ls -lart ~/.kube/config chmod o+r ~/.kube/config # check connectivity to local k8s kubectl cluster-info &>/dev/null # Shut down the KIND cluster unkind: #!/usr/bin/env bash kind delete cluster --name {{cluster_name}} if docker inspect kind-registry &>/dev/null; then echo "Stopping container registry" docker kill kind-registry docker rm kind-registry fi # Bring up the nginx ingress controller on the target k8s cluster nginx: #!/usr/bin/env bash kubectl apply -k https://github.com/hyperledger-labs/fabric-operator.git/config/ingress/{{ cluster_runtime }} sleep 20 kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=3m # Just start the operator operator: operator-crds infrastructure/sample-network/network operator # Just start the console console: operator infrastructure/sample-network/network console # Just install the operator CRDs operator-crds: check-kube kubectl apply -k https://github.com/hyperledger-labs/fabric-operator.git/config/crd ############################################################################### # TEST TARGETS ############################################################################### # Run e2e tests of all scenarios test: test-chaincode test-appdev test-cloud # test-ansible # Run an e2e test of the SmartContractDev scenario test-chaincode: tests/00-chaincode-e2e.sh # Run an e2e test of the ApplicationDev scenario test-appdev: tests/10-appdev-e2e.sh # Run an e2e test of the CloudNative scenario test-cloud: tests/20-cloud-e2e.sh # Run tests of the network setup with operator, console, and ansible plays test-ansible: tests/30-ansible-e2e.sh # Run tests of the console setup using the direct line to kube API controller (not ansible) test-console: tests/40-console.sh ############################################################################### # MICROFAB / DEV TARGETS # ############################################################################### # Shut down the microfab (uf) instance microfab-down: #!/usr/bin/env bash if docker inspect microfab &>/dev/null; then echo "Removing existing microfab container:" docker kill microfab fi # Start a micro fab instance and create configuration in _cfg/uf microfab: microfab-down #!/usr/bin/env bash set -e -o pipefail export CFG=$CWDIR/_cfg/uf export MICROFAB_CONFIG='{ "endorsing_organizations":[ { "name": "org1" }, { "name": "org2" } ], "channels":[ { "name": "mychannel", "endorsing_organizations":[ "org1" ] }, { "name": "appchannel", "endorsing_organizations":[ "org1","org2" ] } ], "capability_level":"V2_5" }' mkdir -p $CFG echo echo "Stating microfab...." timeout 60s bash -c \ 'docker run --name microfab -p 8080:8080 --add-host host.docker.internal:host-gateway --rm -d -e MICROFAB_CONFIG="${MICROFAB_CONFIG}" ghcr.io/hyperledger-labs/microfab:latest \ && docker logs -f microfab | grep --max-count=1 "Microfab started"' curl -s http://console.127-0-0-1.nip.io:8080/ak/api/v1/components | weft microfab -w $CFG/_wallets -p $CFG/_gateways -m $CFG/_msp -f cat << EOF > $CFG/org1admin.env export CORE_PEER_LOCALMSPID=org1MSP export CORE_PEER_MSPCONFIGPATH=$CFG/_msp/org1/org1admin/msp export CORE_PEER_ADDRESS=org1peer-api.127-0-0-1.nip.io:8080 export FABRIC_CFG_PATH=$CWDIR/config export CORE_PEER_CLIENT_CONNTIMEOUT=15s export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s export ORDERER_ENDPOINT=orderer-api.127-0-0-1.nip.io:8080 EOF cat << EOF > $CFG/org2admin.env export CORE_PEER_LOCALMSPID=org2MSP export CORE_PEER_MSPCONFIGPATH=$CFG/_msp/org2/org2admin/msp export CORE_PEER_ADDRESS=org2peer-api.127-0-0-1.nip.io:8080 export FABRIC_CFG_PATH=$CWDIR/config export CORE_PEER_CLIENT_CONNTIMEOUT=15s export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s export ORDERER_ENDPOINT=orderer-api.127-0-0-1.nip.io:8080 EOF echo echo "To get an peer cli environment run:" echo echo 'source $WORKSHOP_PATH/_cfg/uf/org1admin.env' # Creates a chaincode package and install/approve/commit debugcc: #!/usr/bin/env bash set -e -o pipefail export CFG=$CWDIR/_cfg/uf pushd $CWDIR/contracts/asset-transfer-typescript # this is the ip address the peer will use to talk to the CHAINCODE_ID # remember this is relative from where the peer is running. export CHAINCODE_SERVER_ADDRESS=host.docker.internal:9999 export CHAINCODE_ID=$(weft chaincode package caas --path . --label asset-transfer --address ${CHAINCODE_SERVER_ADDRESS} --archive asset-transfer.tgz --quiet) export CORE_PEER_LOCALMSPID=org1MSP export CORE_PEER_MSPCONFIGPATH=$CFG/_msp/org1/org1admin/msp export CORE_PEER_ADDRESS=org1peer-api.127-0-0-1.nip.io:8080 export CORE_PEER_CLIENT_CONNTIMEOUT=15s export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s export ORDERER_ENDPOINT=orderer-api.127-0-0-1.nip.io:8080 echo "CHAINCODE_ID=${CHAINCODE_ID}" set -x && peer lifecycle chaincode install asset-transfer.tgz && { set +x; } 2>/dev/null echo set -x && peer lifecycle chaincode approveformyorg --channelID mychannel -o $ORDERER_ENDPOINT --name asset-transfer -v 0 --package-id $CHAINCODE_ID --sequence 1 --connTimeout 15s && { set +x; } 2>/dev/null echo set -x && peer lifecycle chaincode commit --channelID mychannel -o $ORDERER_ENDPOINT --name asset-transfer -v 0 --sequence 1 --connTimeout 15s && { set +x; } 2>/dev/null echo set -x && peer lifecycle chaincode querycommitted --channelID=mychannel && { set +x; } 2>/dev/null echo popd cat << CC_EOF >> $CFG/org1admin.env export CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 export CHAINCODE_ID=${CHAINCODE_ID} CC_EOF echo "Added CHAINCODE_ID and CHAINCODE_SERVER_ADDRESS to org1admin.env" echo echo ' source $WORKSHOP_PATH/_cfg/uf/org1admin.env' ############################################################################### # CLOUD NATIVE TARGETS # ############################################################################### # Deploy the operator sample network and create a channel cloud-network: cloud-network-down check-kube infrastructure/sample-network/network up # Tear down the operator sample network cloud-network-down: infrastructure/sample-network/network down # Create 'mychannel' cloud-channel: infrastructure/sample-network/network channel create # Check that the cloud setup has been performed check-setup: check # Check that the k8s API controller is ready check-kube: check-setup checks/check-kube.sh # Check that the sample network and channel have been deployed check-network: check-kube checks/check-network.sh # Check that the smart contract has been deployed check-chaincode: check-network checks/check-chaincode.sh # Create 'rest-easy' cloud-rest-easy: infrastructure/sample-network/network rest-easy # Create 'frontend' cloud-frontend: infrastructure/sample-network/network frontend ############################################################################### # ANSIBLE PLAYBOOK TARGETS # ############################################################################### ansible_image := env_var_or_default("ANSIBLE_IMAGE", "ghcr.io/hyperledger-labs/fabric-ansible:latest") namespace := env_var_or_default("WORKSHOP_NAMESPACE", "fabricinfra") # just set up everything with Ansible ansible-doit: ansible-review-config ansible-operator ansible-console ansible-network # Review the Ansible Blockchain Collection configuration in _cfg/ ansible-review-config: #!/usr/bin/env bash mkdir -p ${CWDIR}/_cfg rm -rf ${CWDIR}/_cfg/* || true cp ${CWDIR}/infrastructure/configuration/*.yml ${CWDIR}/_cfg cat ${CWDIR}/infrastructure/configuration/operator-console-vars.yml | envsubst > ${CWDIR}/_cfg/operator-console-vars.yml echo "" echo ">> Fabric Common Configuration" echo "" cat ${CWDIR}/_cfg/fabric-common-vars.yml echo "" echo ">> Fabric Org1 Configuration" echo "" cat ${CWDIR}/_cfg/fabric-org1-vars.yml echo "" echo ">> Fabric Org2 Configuration" echo "" cat ${CWDIR}/_cfg/fabric-org2-vars.yml echo "" echo ">> Fabric Orderer Configuration" echo "" cat ${CWDIR}/_cfg/fabric-ordering-org-vars.yml echo "" echo ">> Fabric Operations Console Configuration" echo "" cat ${CWDIR}/_cfg/operator-console-vars.yml echo "" # Start the Kubernetes fabric-operator with the Ansible Blockchain Collection ansible-ingress: #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi docker run \ --rm \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/_cfg:/_cfg \ -v $(pwd)/infrastructure/kind_console_ingress:/playbooks \ --network=host ${EXTRAS} \ --workdir /playbooks \ {{ansible_image}} \ ansible-playbook /playbooks/90-KIND-ingress.yml # Start the Kubernetes fabric-operator with the Ansible Blockchain Collection ansible-operator: #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi docker run \ --rm \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/_cfg:/_cfg \ -v $(pwd)/infrastructure/operator_console_playbooks:/playbooks ${EXTRAS} \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/01-operator-install.yml # Start the Fabric Operations Console with the Ansible Blockchain Collection ansible-console: #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi docker run \ --rm \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v $(pwd)/infrastructure/operator_console_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/02-console-install.yml ansible-auth: #!/usr/bin/env bash set -ex -o pipefail AUTH=$(curl -X POST https://{{namespace}}-hlf-console-console.{{ingress_domain}}:443/ak/api/v2/permissions/keys -u admin:password -k -H 'Content-Type: application/json' -d '{"roles": ["writer", "manager"],"description": "newkey"}') KEY=$(echo $AUTH | jq .api_key | tr -d '"') SECRET=$(echo $AUTH | jq .api_secret | tr -d '"') echo "Writing authentication file for Ansible based IBP (Software) network building" cat << EOF > $CWDIR/_cfg/auth-vars.yml api_key: $KEY api_endpoint: https://{{namespace}}-hlf-console-console.{{ingress_domain}}/ api_authtype: basic api_secret: $SECRET EOF cat ${CWDIR}/_cfg/auth-vars.yml # Build a sample Fabric network with the Ansible Blockchain Collection ansible-network: ansible-auth #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi docker run \ --rm \ -u $(id -u) \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/infrastructure/fabric_network_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/00-complete.yml # Bring down the sample network created with the Ansible Blockchain Collection ansible-network-down: #!/usr/bin/env bash set -ex -o pipefail kubectl delete namespace {{ namespace }} --ignore-not-found # Build a chaincode package with Ansible Blockchain Collection ansible-build-chaincode: #!/usr/bin/env bash set -ex -o pipefail pushd ${CWDIR}/contracts/asset-transfer-typescript if [ "{{cluster_runtime}}" = "openshift" ]; then export IMAGE_NAME="{{namespace}}/{{chaincode_name}}" else export IMAGE_NAME="{{chaincode_name}}" fi DOCKER_BUILDKIT=1 docker build -t {{external_repo_endpoint}}/${IMAGE_NAME} . --target k8s docker push {{external_repo_endpoint}}/${IMAGE_NAME} # note the double { } for escaping export IMG_SHA=$(docker inspect --format='{{{{index .RepoDigests 0}}' {{external_repo_endpoint}}/${IMAGE_NAME} | cut -d'@' -f2) weft chaincode package k8s --name {{internal_repo_endpoint}}/${IMAGE_NAME} --digest ${IMG_SHA} --label {{chaincode_name}} mv {{chaincode_name}}.tgz ${CWDIR}/_cfg popd # Deploy a chaincode package with the Ansible Blockchain Collection ansible-deploy-chaincode: #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi # cp ${CWDIR}/contracts/asset-transfer-typescript/asset-transfer-chaincode-vars.yml ${CWDIR}/_cfg docker run \ --rm \ -u $(id -u) \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/infrastructure/production_chaincode_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/19-install-and-approve-chaincode.yml docker run \ --rm \ -u $(id -u) \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/infrastructure/production_chaincode_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/20-install-and-approve-chaincode.yml docker run \ --rm \ -u $(id -u) \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/infrastructure/production_chaincode_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/21-commit-chaincode.yml # Creates a new identity for an application to use ansible-ready-application: #!/usr/bin/env bash set -ex -o pipefail export EXTRAS="" if [ -f "/_cfg/k8s_context.yaml" ]; then export EXTRAS=" -e KUBECONFIG=/_cfg/k8s_context.yaml" fi docker run \ --rm \ -u $(id -u) \ -v ${HOME}/.kube/:/home/hlf-user/.kube/ \ -v ${CWDIR}/infrastructure/production_chaincode_playbooks:/playbooks ${EXTRAS} \ -v ${CWDIR}/_cfg:/_cfg \ --network=host \ {{ansible_image}} \ ansible-playbook /playbooks/22-register-application.yml