From e5283bf129d86a37ecf9ce6ad0d56ce807c32d97 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 31 Oct 2024 13:50:20 +0100 Subject: [PATCH] Prepare release 1.11 (#240) * update docs * Fix deploy github pages Signed-off-by: David VIEJO * change leader rotation Signed-off-by: David VIEJO * Update Signed-off-by: David VIEJO * Update readme Signed-off-by: David VIEJO * Verify migration Raft -> BFT Signed-off-by: David VIEJO --------- Signed-off-by: David VIEJO --- .github/workflows/release_web.yml | 11 +- README.md | 35 +- .../mainchannel/mainchannel_controller.go | 13 +- scripts/migrate-channel-raft-bft.ts | 106 ++ .../docs/intro/getting-started-3-0.md | 912 ++++++++++++++++++ website-docs/docs/intro/getting-started.md | 273 ++++-- website-docs/sidebars.ts | 2 +- 7 files changed, 1243 insertions(+), 109 deletions(-) create mode 100644 website-docs/docs/intro/getting-started-3-0.md diff --git a/.github/workflows/release_web.yml b/.github/workflows/release_web.yml index 5a43f888..28073cd1 100644 --- a/.github/workflows/release_web.yml +++ b/.github/workflows/release_web.yml @@ -7,11 +7,16 @@ on: jobs: deploy: - name: Deploy to GitHub Pages + name: Deploy to GitHub Page runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + - name: Setup Bun uses: oven-sh/setup-bun@v1 with: @@ -28,12 +33,12 @@ jobs: - name: Install dependencies run: | cd website-docs - bun install + yarn install --frozen-lockfile - name: Build Docusaurus website run: | cd website-docs - bun run build + yarn run build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 diff --git a/README.md b/README.md index 7983b357..49f713ba 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ To install helm: [https://helm.sh/docs/intro/install/](https://helm.sh/docs/intr ```bash helm repo add kfs https://kfsoftware.github.io/hlf-helm-charts --force-update -helm install hlf-operator --version=1.10.0 -- kfs/hlf-operator +helm install hlf-operator --version=1.11.0-beta8-1 -- kfs/hlf-operator ``` @@ -218,36 +218,19 @@ EOF ## Deploy a `Peer` organization -### Environment Variables for AMD (Default) +### Environment Variables ```bash export PEER_IMAGE=hyperledger/fabric-peer -export PEER_VERSION=2.5.10 +export PEER_VERSION=3.0.0 export ORDERER_IMAGE=hyperledger/fabric-orderer -export ORDERER_VERSION=2.5.10 +export ORDERER_VERSION=3.0.0 export CA_IMAGE=hyperledger/fabric-ca export CA_VERSION=1.5.13 ``` - -### Environment Variables for ARM (Mac M1) - -```bash -export PEER_IMAGE=hyperledger/fabric-peer -export PEER_VERSION=2.5.10 - -export ORDERER_IMAGE=hyperledger/fabric-orderer -export ORDERER_VERSION=2.5.10 - -export CA_IMAGE=hyperledger/fabric-ca -export CA_VERSION=1.5.13 - -``` - - - ### Configure Internal DNS ```bash @@ -704,8 +687,6 @@ echo "PACKAGE_ID=$PACKAGE_ID" kubectl hlf chaincode install --path=./chaincode.tgz \ --config=org1.yaml --language=golang --label=$CHAINCODE_LABEL --user=admin --peer=org1-peer0.default -kubectl hlf chaincode install --path=./chaincode.tgz \ - --config=org1.yaml --language=golang --label=$CHAINCODE_LABEL --user=admin --peer=org1-peer1.default ``` @@ -735,14 +716,14 @@ export VERSION="1.0" kubectl hlf chaincode approveformyorg --config=org1.yaml --user=admin --peer=org1-peer0.default \ --package-id=$PACKAGE_ID \ --version "$VERSION" --sequence "$SEQUENCE" --name=asset \ - --policy="OR('Org1MSP.member')" --channel=testbft02 + --policy="OR('Org1MSP.member')" --channel=demo ``` ## Commit chaincode ```bash kubectl hlf chaincode commit --config=org1.yaml --user=admin --mspid=Org1MSP \ --version "$VERSION" --sequence "$SEQUENCE" --name=asset \ - --policy="OR('Org1MSP.member')" --channel=testbft02 + --policy="OR('Org1MSP.member')" --channel=demo ``` @@ -751,7 +732,7 @@ kubectl hlf chaincode commit --config=org1.yaml --user=admin --mspid=Org1MSP \ ```bash kubectl hlf chaincode invoke --config=org1.yaml \ --user=admin --peer=org1-peer0.default \ - --chaincode=asset --channel=testbft02 \ + --chaincode=asset --channel=demo \ --fcn=initLedger -a '[]' ``` @@ -760,7 +741,7 @@ kubectl hlf chaincode invoke --config=org1.yaml \ ```bash kubectl hlf chaincode query --config=org1.yaml \ --user=admin --peer=org1-peer0.default \ - --chaincode=asset --channel=testbft02 \ + --chaincode=asset --channel=demo \ --fcn=GetAllAssets -a '[]' ``` diff --git a/controllers/mainchannel/mainchannel_controller.go b/controllers/mainchannel/mainchannel_controller.go index 9750175a..ca8c282d 100644 --- a/controllers/mainchannel/mainchannel_controller.go +++ b/controllers/mainchannel/mainchannel_controller.go @@ -876,11 +876,9 @@ func (r *FabricMainChannelReconciler) mapToConfigTX(channel *hlfv1alpha1.FabricM }, } // if etcdraft, add BlockValidation policy - if channel.Spec.ChannelConfig.Orderer.OrdererType == hlfv1alpha1.OrdererConsensusEtcdraft { - adminOrdererPolicies["BlockValidation"] = configtx.Policy{ - Type: "ImplicitMeta", - Rule: "ANY Writers", - } + adminOrdererPolicies["BlockValidation"] = configtx.Policy{ + Type: "ImplicitMeta", + Rule: "ANY Writers", } var state orderer.ConsensusState @@ -919,7 +917,6 @@ func (r *FabricMainChannelReconciler) mapToConfigTX(channel *hlfv1alpha1.FabricM ServerTlsCert: utils.EncodeX509Certificate(serverTLSCert), }) } - // leader_rotation := sb.Options_ROTATION_ON if channel.Spec.ChannelConfig.Orderer.SmartBFT.LeaderRotation == sb.Options_ROTATION_ON { @@ -977,7 +974,7 @@ func (r *FabricMainChannelReconciler) mapToConfigTX(channel *hlfv1alpha1.FabricM ordConfigtx := configtx.Orderer{ OrdererType: ordererType, Organizations: ordererOrgs, - ConsenterMapping: consenterMapping, // TODO: map from channel.Spec.ConssenterMapping + ConsenterMapping: consenterMapping, SmartBFT: smartBFTOptions, EtcdRaft: etcdRaft, Policies: adminOrdererPolicies, @@ -1452,7 +1449,7 @@ func updateOrdererChannelConfigTx(currentConfigTX configtx.ConfigTx, newConfigTx } // update - if ord.OrdererType == "BFT" { + if ord.OrdererType == orderer.ConsensusTypeBFT { err = currentConfigTX.Orderer().SetConfiguration(newConfigTx.Orderer) if err != nil { return errors.Wrapf(err, "failed to set orderer configuration") diff --git a/scripts/migrate-channel-raft-bft.ts b/scripts/migrate-channel-raft-bft.ts index 6aa3f5a1..44329ea3 100644 --- a/scripts/migrate-channel-raft-bft.ts +++ b/scripts/migrate-channel-raft-bft.ts @@ -549,6 +549,103 @@ async function updatePeers(peers: { name: string; namespace: string }[]) { } } +async function restartOrderers(orderers: { name: string; namespace: string }[]) { + for (const orderer of orderers) { + try { + console.log(`Restarting orderer ${orderer.name} in namespace ${orderer.namespace}...`) + const appsV1Api = kc.makeApiClient(k8s.AppsV1Api) + + // Scale down to 0 + const patch = [ + { + op: 'replace', + path: '/spec/replicas', + value: 0, + }, + ] + + await appsV1Api.patchNamespacedDeployment(orderer.name, orderer.namespace, patch, undefined, undefined, undefined, undefined, undefined, { + headers: { 'Content-Type': 'application/json-patch+json' }, + }) + await new Promise((resolve) => setTimeout(resolve, 1000)) + // Wait for scale down by polling the deployment state + let scaledDown = false + const maxWaitTime = 10 * 60 * 1000 // 10 minutes in milliseconds + const pollInterval = 1000 // 1 second + const startTime = Date.now() + + while (!scaledDown && Date.now() - startTime < maxWaitTime) { + try { + const res = await appsV1Api.readNamespacedDeployment(orderer.name, orderer.namespace) + const deployment = res.body + const isReady = + deployment.status?.conditions?.some((condition) => condition.type === 'Available' && condition.status === 'True') && + deployment.status?.readyReplicas === deployment.status?.replicas + + if (isReady) { + scaledDown = true + console.log(`Orderer ${orderer.name} in namespace ${orderer.namespace} has been scaled down to 0`) + } else { + const elapsedTime = Math.floor((Date.now() - startTime) / 1000) + console.log(`Waiting for orderer ${orderer.name} in namespace ${orderer.namespace} to scale down (${elapsedTime} seconds elapsed)...`) + await new Promise((resolve) => setTimeout(resolve, pollInterval)) + } + } catch (err) { + console.error(`Error checking orderer ${orderer.name} in namespace ${orderer.namespace} scale down status:`, err) + await new Promise((resolve) => setTimeout(resolve, pollInterval)) + } + } + + if (!scaledDown) { + console.error(`Orderer ${orderer.name} in namespace ${orderer.namespace} did not scale down within the expected time.`) + continue + } + + // Scale back up to 1 + patch[0].value = 1 + await appsV1Api.patchNamespacedDeployment(orderer.name, orderer.namespace, patch, undefined, undefined, undefined, undefined, undefined, { + headers: { 'Content-Type': 'application/json-patch+json' }, + }) + + // Wait for the orderer to be back up by polling the deployment state + let ready = false + const startTimeUp = Date.now() + await new Promise((resolve) => setTimeout(resolve, 1000)) + + while (!ready && Date.now() - startTimeUp < maxWaitTime) { + try { + const res = await appsV1Api.readNamespacedDeployment(orderer.name, orderer.namespace) + const deployment = res.body + + const isReady = + deployment.status?.conditions?.some((condition) => condition.type === 'Available' && condition.status === 'True') && + deployment.status?.readyReplicas === deployment.status?.replicas + + if (isReady) { + ready = true + console.log(`Orderer ${orderer.name} in namespace ${orderer.namespace} is back up and ready`) + } else { + const elapsedTime = Math.floor((Date.now() - startTimeUp) / 1000) + console.log(`Waiting for orderer ${orderer.name} in namespace ${orderer.namespace} to be back up (${elapsedTime} seconds elapsed)...`) + await new Promise((resolve) => setTimeout(resolve, pollInterval)) + } + } catch (err) { + console.error(`Error checking orderer ${orderer.name} in namespace ${orderer.namespace} status:`, err) + await new Promise((resolve) => setTimeout(resolve, pollInterval)) + } + } + + if (!ready) { + console.error(`Orderer ${orderer.name} in namespace ${orderer.namespace} did not become ready within the expected time.`) + } else { + console.log(`Successfully restarted orderer ${orderer.name}`) + } + } catch (err) { + console.error(`Error restarting orderer ${orderer.name}:`, err) + } + } +} + async function main() { const channelName = await input({ message: 'Enter the channel name:' }) const channel = await getChannelFromKubernetes(channelName) @@ -624,6 +721,15 @@ async function main() { await updateChannelToBFT(channelName) } + // Add restart confirmation + const restartConfirmed = await confirm({ + message: `Restart the orderers before setting channel to normal state?`, + default: true, + }) + if (restartConfirmed) { + await restartOrderers(selectedOrderers) + } + const stateNormalConfirmed = await confirm({ message: `Set channel ${channelName} to STATE_NORMAL?`, default: true, diff --git a/website-docs/docs/intro/getting-started-3-0.md b/website-docs/docs/intro/getting-started-3-0.md new file mode 100644 index 00000000..4591f3db --- /dev/null +++ b/website-docs/docs/intro/getting-started-3-0.md @@ -0,0 +1,912 @@ +--- +id: getting-started-3-0 +title: Getting started with Hyperledger Fabric 3.0 +--- + +# Hyperledger Fabric 3.0 + +This workshop is divided in this steps: + +1. [Create kubernetes cluster](#1-create-kubernetes-cluster) +2. [Install and configure Istio](#2-install-and-configure-istio) +3. [Install Hyperledger Fabric operator](#3-install-hyperledger-fabric-operator) +4. [Deploy a peer organization](#4-deploy-a-peer-organization) +5. [Deploy an orderer organization](#5-deploy-an-orderer-organization) +6. [Create a channel](#6-create-a-channel) +7. [Join peer to the channel](#7-join-peer-to-the-channel) +8. [Install a chaincode](#8-install-a-chaincode) +9. [Deploy chaincode container on cluster](#9-deploy-chaincode-container-on-cluster) +10. [Approve chaincode](#10-approve-chaincode) +11. [Commit chaincode](#11-commit-chaincode) +12. [Invoke a transaction on the channel](#12-invoke-a-transaction-on-the-channel) +13. [Query assets in the channel](#13-query-assets-in-the-channel) +14. [Completion](#14-completion) + +In order to follow the workshop, you have two options, follow the Loom video or follow the steps below. + +Run through the steps explaining what we are going to do and how to do it. + +## 1. Create kubernetes cluster + +To start deploying our red fabric we have to have a Kubernetes cluster. For this we will use KinD. + +Ensure you have these ports available before creating the cluster: + +- 80 +- 443 + +If these ports are not available this tutorial will not work. + +### Using K3D + +```bash +k3d cluster create -p "80:30949@agent:0" -p "443:30950@agent:0" --agents 2 k8s-hlf +``` + +### Using KinD + +```bash +cat << EOF > kind-config.yaml +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + image: kindest/node:v1.27.3 + extraPortMappings: + - containerPort: 30949 + hostPort: 80 + - containerPort: 30950 + hostPort: 443 +EOF + +kind create cluster --config=./kind-config.yaml + +``` + +## 2. Install and configure Istio + +Install Istio binaries on the machine: + +```bash +# add TARGET_ARCH=x86_64 if you are using arm64 +curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.20.0 sh - +export PATH="$PATH:$PWD/istio-1.20.0/bin" +``` + +Install Istio on the Kubernetes cluster: + +```bash + +kubectl create namespace istio-system + +istioctl operator init + +kubectl apply -f - < org1.yaml +``` + +### Create metadata file + +```bash +# remove the code.tar.gz chaincode.tgz if they exist +rm code.tar.gz chaincode.tgz +export CHAINCODE_NAME=asset +export CHAINCODE_LABEL=asset +cat << METADATA-EOF > "metadata.json" +{ + "type": "ccaas", + "label": "${CHAINCODE_LABEL}" +} +METADATA-EOF +``` + +### Prepare connection file + +```bash +## chaincode as a service +cat > "connection.json" < kind-config.yaml kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane + image: kindest/node:v1.30.2 extraPortMappings: - containerPort: 30949 hostPort: 80 @@ -47,7 +118,7 @@ To install helm: [https://helm.sh/docs/intro/install/](https://helm.sh/docs/intr ```bash helm repo add kfs https://kfsoftware.github.io/hlf-helm-charts --force-update -helm install hlf-operator --version=1.8.0 kfs/hlf-operator +helm install hlf-operator --version=1.10.0 -- kfs/hlf-operator ``` @@ -75,6 +146,9 @@ Install Istio on the Kubernetes cluster: kubectl create namespace istio-system +export ISTIO_PATH=$(echo $PWD/istio-*/bin) +export PATH="$PATH:$ISTIO_PATH" + istioctl operator init kubectl apply -f - <