diff --git a/.env b/.env index 4ac0218..9e79cdc 100644 --- a/.env +++ b/.env @@ -63,9 +63,15 @@ FABKIT_COUCHDB_IMAGE="couchdb:3.1.1" # HYPERLEDGER EXPLORER ######################################## FABKIT_EXPLORER_PATH="${FABKIT_ROOT}/explorer" -FABKIT_EXPLORER_VERSION=1.1.3 -FABKIT_GRAFANA_VERSION=7.2.0 -FABKIT_PROMETHEUS_VERSION=v2.21.0 +# todo: set to fixed version. it does not work for apple silicon (workaround: build locally) +FABKIT_EXPLORER_VERSION=latest +FABKIT_GRAFANA_VERSION=8.2.2 +FABKIT_PROMETHEUS_VERSION=v2.30.3 +######################################## +# HYPERLEDGER FABRIC CONSOLE +######################################## +FABKIT_CONSOLE_PATH="${FABKIT_ROOT}/console" +FABKIT_CONSOLE_VERSION=latest ######################################## # THIRD PARTY ######################################## diff --git a/.gitignore b/.gitignore index a99feac..f59c702 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,20 @@ debug* vendor/ -dist/ .idea/ - logs/ *.log* - -network/cryptos/ -network/channels/ -data/ -docker.sock - .DS_Store *.tar* *.zip binary binary_test - go.sum *.pem + +console/assets/ +dist/ explorer/connection-profile/first-network.json network/config/configtx.yaml +network/cryptos/ +network/channels/ .lastrun \ No newline at end of file diff --git a/README.md b/README.md index 0138334..5ba162a 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,31 @@ fabkit explorer stop Note: If you are using _docker-machine_ replace `localhost` with the docker-machine IP address. You can find this out by running `docker-machine ip`. +## Fabric Operations Console (aka IBM Blockchain Platform UI) + +![Fabric Operations Console: Dashboard](./docs/images/console1.jpg) + +Fabric Operations Console provides functionalities to manage Hyperledger Fabric components (peers, CAs, orderers) and perform operations on the network like installing, instantiating, upgrading chaincodes or creating new channels. + +To start the console components: + +```bash +fabkit console start +``` + +To stop and remove all console running components: + +```bash +fabkit console stop +``` + +Accessing the console: + +- Username: `admin` | Password: `password` +- Host: [http://localhost:3000](http://localhost:3000) + +For additional information on how to configure and use the console check the [Fabric Operations Console](./docs/console.md) page. + ## Register and enroll users Fabkit offers full support to interact with a Fabric CA. To have a complete overview of the all available commands visit the [Fabric CA and user certificates management](./docs/ca.md) page. diff --git a/console/docker-compose.yaml b/console/docker-compose.yaml new file mode 100644 index 0000000..2635237 --- /dev/null +++ b/console/docker-compose.yaml @@ -0,0 +1,84 @@ +version: "2.4" + +networks: + default: + external: + # This value should be the same for fabric network and client + name: ${FABKIT_DOCKER_NETWORK} + +volumes: + console-couchdb: + name: ${FABKIT_DOCKER_NETWORK}_console-couchdb + +services: + fabric-console: + container_name: fabric-console + image: ghcr.io/hyperledger-labs/fabric-console:latest + ports: + - "3000:3000" + volumes: + - ${FABKIT_HOST_ROOT}/console/env:/home/athena/env + environment: + - CONFIGURE_FILE=./env/config.yaml + - DB_CONNECTION_STRING=http://admin:password@console-couchdb:5984 + - DB_SYSTEM=athena_system + + configtxlator: + container_name: configtxlator + image: hyperledger/fabric-tools:${FABKIT_FABRIC_VERSION} + command: /bin/bash -c "/usr/local/bin/configtxlator start --CORS=*" + ports: + - "7059:7059" + + console-couchdb: + container_name: console-couchdb + extends: + file: ${FABKIT_NETWORK_PATH}/base/base.yaml + service: couchdb-base + environment: + - COUCHDB_USER=admin + - COUCHDB_PASSWORD=password + volumes: + - "console-couchdb:/opt/couchdb/data" + ports: + - "5985:5984" + + proxy.peer0.org1.example.com: + container_name: proxy.peer0.org1.example.com + image: ghcr.io/hyperledger-labs/grpc-web:latest + environment: + - BACKEND_ADDRESS=peer0.org1.example.com:7051 + - SERVER_TLS_CERT_FILE=/certs/tls/server.crt + - SERVER_TLS_KEY_FILE=/certs/tls/server.key + - BACKEND_TLS_CA_FILES=/certs/tls/ca.crt + - SERVER_BIND_ADDRESS=0.0.0.0 + - SERVER_HTTP_DEBUG_PORT=8080 + - SERVER_HTTP_TLS_PORT=7443 + - BACKEND_TLS=true + - SERVER_HTTP_MAX_WRITE_TIMEOUT=5m + - SERVER_HTTP_MAX_READ_TIMEOUT=5m + - USE_WEBSOCKETS=true + volumes: + - ${FABKIT_HOST_ROOT}/network/cryptos/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/certs/tls + ports: + - "7443:7443" + + proxy.orderer.example.com: + container_name: proxy.orderer.example.com + image: ghcr.io/hyperledger-labs/grpc-web:latest + environment: + - BACKEND_ADDRESS=orderer.example.com:7050 + - SERVER_TLS_CERT_FILE=/certs/tls/server.crt + - SERVER_TLS_KEY_FILE=/certs/tls/server.key + - BACKEND_TLS_CA_FILES=/certs/tls/ca.crt + - SERVER_BIND_ADDRESS=0.0.0.0 + - SERVER_HTTP_DEBUG_PORT=8082 + - SERVER_HTTP_TLS_PORT=7445 + - BACKEND_TLS=true + - SERVER_HTTP_MAX_WRITE_TIMEOUT=5m + - SERVER_HTTP_MAX_READ_TIMEOUT=5m + - USE_WEBSOCKETS=true + volumes: + - ${FABKIT_HOST_ROOT}/network/cryptos/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/certs/tls + ports: + - "7445:7445" diff --git a/console/env/config.yaml b/console/env/config.yaml new file mode 100644 index 0000000..09ad781 --- /dev/null +++ b/console/env/config.yaml @@ -0,0 +1,8 @@ +--- +version: v1.0 +app_port: 3000 +auth_scheme: couchdb +initial_admin: admin +configtxlator_url_original: http://localhost:7059 +host_url: http://localhost:3000 +default_user_password_initial: password diff --git a/console/templates/Certificate_Authorities/ordererca-local_ca.json b/console/templates/Certificate_Authorities/ordererca-local_ca.json new file mode 100644 index 0000000..83a3f17 --- /dev/null +++ b/console/templates/Certificate_Authorities/ordererca-local_ca.json @@ -0,0 +1,11 @@ +{ + "display_name": "ordererca - local", + "api_url": "https://ca_orderer:9054", + "operations_url": "http://ca_orderer:19054", + "ca_url": "https://ca_orderer:9054", + "type": "fabric-ca", + "ca_name": "ca-orderer", + "tlsca_name": "ca-orderer", + "tls_cert": "", + "name": "ordererca - local" +} diff --git a/console/templates/Certificate_Authorities/orgca-local_ca.json b/console/templates/Certificate_Authorities/orgca-local_ca.json new file mode 100644 index 0000000..8d2ff0a --- /dev/null +++ b/console/templates/Certificate_Authorities/orgca-local_ca.json @@ -0,0 +1,11 @@ +{ + "display_name": "org%ORG%ca - local", + "api_url": "https://ca.org%ORG%.example.com:7054", + "operations_url": "http://ca.org%ORG%.example.com:1%PORT_INDEX%054", + "ca_url": "https://ca.org%ORG%.example.com:7054", + "name": "org%ORG%ca - local", + "type": "fabric-ca", + "ca_name": "ca.org%ORG%.example.com", + "tlsca_name": "ca.org%ORG%.example.com", + "tls_cert": "" +} diff --git a/console/templates/Ordering_Services/orderer-local_orderer.json b/console/templates/Ordering_Services/orderer-local_orderer.json new file mode 100644 index 0000000..7fcbc10 --- /dev/null +++ b/console/templates/Ordering_Services/orderer-local_orderer.json @@ -0,0 +1,30 @@ +{ + "display_name": "ordering node - local", + "grpcwp_url": "https://proxy.orderer.example.com:7445", + "api_url": "grpcs://orderer.example.com:7050", + "operations_url": "http://orderer.example.com:17050", + "type": "fabric-orderer", + "msp_id": "OrdererMSP", + "system_channel_id": "orderer-system-channel", + "cluster_id": "kcfhqzuxci", + "cluster_name": "orderer_local", + "name": "ordering node - local", + "msp": { + "component": { + "tls_cert": "" + }, + "ca": { + "root_certs": [ + "" + ] + }, + "tlsca": { + "root_certs": [ + "" + ] + } + }, + "pem": "", + "tls_cert": "", + "tls_ca_root_cert": "" +} \ No newline at end of file diff --git a/console/templates/Organizations/orderermsp_msp.json b/console/templates/Organizations/orderermsp_msp.json new file mode 100644 index 0000000..2d52902 --- /dev/null +++ b/console/templates/Organizations/orderermsp_msp.json @@ -0,0 +1,33 @@ +{ + "display_name": "Orderer MSP", + "msp_id": "OrdererMSP", + "type": "msp", + "admins": [], + "root_certs": [ + "" + ], + "tls_root_certs": [ + "" + ], + "fabric_node_ous": { + "admin_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "admin" + }, + "client_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "client" + }, + "enable": true, + "orderer_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "orderer" + }, + "peer_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "peer" + } + }, + "host_url": "http://localhost:3002", + "name": "Orderer MSP" +} diff --git a/console/templates/Organizations/orgmsp_msp.json b/console/templates/Organizations/orgmsp_msp.json new file mode 100644 index 0000000..a15b388 --- /dev/null +++ b/console/templates/Organizations/orgmsp_msp.json @@ -0,0 +1,33 @@ +{ + "display_name": "Org%ORG% MSP", + "msp_id": "Org%ORG%MSP", + "type": "msp", + "admins": [], + "root_certs": [ + "" + ], + "tls_root_certs": [ + "" + ], + "fabric_node_ous": { + "admin_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "admin" + }, + "client_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "client" + }, + "enable": true, + "orderer_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "orderer" + }, + "peer_ou_identifier": { + "certificate": "", + "organizational_unit_identifier": "peer" + } + }, + "host_url": "http://localhost:3002", + "name": "Org%ORG% MSP" +} \ No newline at end of file diff --git a/console/templates/Peers/org_peer-local_peer.json b/console/templates/Peers/org_peer-local_peer.json new file mode 100644 index 0000000..53acffa --- /dev/null +++ b/console/templates/Peers/org_peer-local_peer.json @@ -0,0 +1,28 @@ +{ + "display_name": "org%ORG%_peer0 - local", + "grpcwp_url": "https://proxy.peer0.org%ORG%.example.com:%PORT_INDEX%443", + "api_url": "grpcs://peer0.org%ORG%.example.com:%PORT_INDEX%051", + "operations_url": "http://peer0.org%ORG%.example.com:1%PORT_INDEX%051", + "msp_id": "Org%ORG%MSP", + "name": "org%ORG%_peer0 - local", + "type": "fabric-peer", + "msp": { + "component": { + "admin_certs": [], + "tls_cert": "" + }, + "ca": { + "root_certs": [ + "" + ] + }, + "tlsca": { + "root_certs": [ + "" + ] + } + }, + "pem": "", + "tls_cert": "", + "tls_ca_root_cert": "" +} diff --git a/docs/console.md b/docs/console.md new file mode 100644 index 0000000..ee0dc9a --- /dev/null +++ b/docs/console.md @@ -0,0 +1,96 @@ +# Fabric Operations Console + +![Fabric Operations Console: Dashboard](./images/console1.jpg) + +![Fabric Operations Console: Channels](./images/console2.jpg) + +The console provides the following high level functionalities: + +- Ability to import and manage all Hyperledger Fabric Components from a single web console, no matter where they are located. +- Maintain complete control over identities, channels, and smart contracts. +- Join Peers to Channels and view channel membership as well as individual transactions and channel details. +- Register, view, delete, and re-enroll CA Users. +- View Ordering cluster and node information as well as view and modify consortium and channel membership. +- View and modify channel capabilities and ordering service parameters. +- Install and Instantiate chaincode. Supports both 1.x and 2.x Lifecycle. +- View, Create, Import and Export Organizations and Identities. +- Role Based Access Control in UI to tightly control which Console users can perform which operations. + +To start the console components: + +```bash +fabkit console start +``` + +To stop and remove all console running components: + +```bash +fabkit console stop +``` + +## Accessing the console + +- Username: `admin` | Password: `password` +- Host: [http://localhost:3000](http://localhost:3000) + +Note: If you are using _docker-machine_ replace `localhost` with the docker-machine IP address. You can find this out by running `docker-machine ip`. + +## Setting up + +### Access the dashboard + +- Open the console at [http://localhost:3000](http://localhost:3000) +- Change the password (only once) +- Access with new credentials + +### Import components information + +- Access the console dashboard and from the menu on the left, switch to _Settings_ page +- Under _Bulk data management_ click on _Import_ +- Select the zip file `console_assets.zip` you will find in `${FABKIT_ROOT}/dist` and click on _Import_ + +### Create Identities + +From the menu on the left, switch to _Nodes_ page and for each component in _Certificate Authorities_ perform the following steps: + +- Click on the CA component to access the CA details page +- Click on _Associate Identity_ +- Enter enroll id `admin` and secret `adminpw` and click on _Associate Identity_ +- A new _admin_ user will be added to the list +- Select _Register user_ +- Choose enroll id and secret for the admin user that will manage your organization, for example, for Org1MSP, simple mnemonic credentials could be `org1msp-admin` and `org1msp-adminpw` +- Select `admin` under _Type_ +- Then click _Next_ and finally on _Register User_ +- A new identity will be added to the _Registered Users_ table +- Select the overflow menu (3 dots) on the right of this newly created user +- Select _Enroll identity_ +- Use the same secret (e.g. `org1msp-adminpw`) as from step above and then click _Next_ +- Enter identity display name as `MSP_ORG_NAME Admin` (e.g. `Org1MSP Admin`) and click _Add Identity to wallet_ + +The outcome of these steps should be: + +- 2 users in the _Registered Users_ table +- User `admin` with _client_ role +- The other user with _admin_ role (**necessary for performing operations on the console**) + +### Associate Identity + +From the menu on the left, switch to _Nodes_ page and for each peer and orderer component perform the following steps: + +- Select a component +- Click on _Associate Identity_ +- Select the appropriate `admin` identity (e.g. `Org1MSP Admin` for peers in `Org1MSP`) and click _Associate Identity_ + +## Data persistency + +All components settings and credentials are stored into a CouchDB database and accessible via browser. + +- Username: `admin` | Password: `password` +- Host: [http://localhost:5985/_utils/](http://localhost:5985/_utils/) + +However, very much in line with web3 hold-your-own-key philosophy, all the private keys of enrolled identities are stored locally in your browser, therefore cleaning up the cache will automatically remove all the entities from your wallet (not from the CA!). If that happens, as long as your remember the _secret_, you will still be able to re-enroll those entities and recover their credentials. +**It is good practice to note the secret down and export those entities from the wallet.** + +## References + +- [Fabric Operations Console - Official repository](https://github.com/hyperledger-labs/fabric-operations-console) diff --git a/docs/images/console1.jpg b/docs/images/console1.jpg new file mode 100644 index 0000000..7e40e69 Binary files /dev/null and b/docs/images/console1.jpg differ diff --git a/docs/images/console2.jpg b/docs/images/console2.jpg new file mode 100644 index 0000000..b133ad1 Binary files /dev/null and b/docs/images/console2.jpg differ diff --git a/explorer/docker-compose.yaml b/explorer/docker-compose.yaml index 79ac47e..62ca31c 100644 --- a/explorer/docker-compose.yaml +++ b/explorer/docker-compose.yaml @@ -72,4 +72,4 @@ services: - ${FABKIT_HOST_ROOT}/explorer/artifacts/operations/grafana_conf/provisioning:/etc/grafana/provisioning - grafana:/var/lib/grafana ports: - - 3000:3000 + - 3333:3000 diff --git a/fabkit b/fabkit index 352e5bc..770ba42 100755 --- a/fabkit +++ b/fabkit @@ -160,8 +160,7 @@ if [ "$FUNC" = "network" ]; then elif [ "$PARAM" = "stop" ]; then __load_lastrun __log_setup - (stop_network) & - __spinner + __check_docker_volumes else help_network exit @@ -178,6 +177,19 @@ elif [ "$FUNC" = "explorer" ]; then help_explorer exit fi +elif [ "$FUNC" = "console" ]; then + __load_lastrun + PARAM="$1" + shift || true + if [ "$PARAM" = "start" ]; then + start_console + elif [ "$PARAM" = "stop" ]; then + (stop_console) & + __spinner + else + help_console + exit + fi elif [ "$FUNC" = "dep" ]; then PARAM="$1" shift || true diff --git a/network/base/base.yaml b/network/base/base.yaml index b4e8d42..12523d0 100644 --- a/network/base/base.yaml +++ b/network/base/base.yaml @@ -20,8 +20,15 @@ services: - CORE_PEER_ADDRESSAUTODETECT=false - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false # whether this node is the org leader, default to false - - CORE_PEER_GOSSIP_EXTERNALENDPOINT=0.0.0.0:7051 # change to external addr for peers in other orgs - - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9443 # operation RESTful API + - CORE_PEER_ID=peer0.org1.example.com + - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 + - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 + - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 + - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 + - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:17051 - CORE_METRICS_PROVIDER=prometheus # prometheus will pull metrics from fabric via /metrics RESTful API - CORE_PEER_PROFILE_ENABLED=false - CORE_PEER_TLS_ENABLED=${FABKIT_TLS_ENABLED} @@ -33,10 +40,6 @@ services: - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer - expose: - - "7051" # gRPC - - "9443" # Operation REST - #command: bash -c 'bash /tmp/peer_build.sh; peer node start' command: peer node start orderer-base: @@ -55,7 +58,6 @@ services: - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp - ORDERER_GENERAL_LEDGERTYPE=file #- ORDERER_GENERAL_LEDGERTYPE=json # default: file - - ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:8443 # operation RESTful API - ORDERER_METRICS_PROVIDER=prometheus # prometheus will pull metrics from orderer via /metrics RESTful API #- ORDERER_RAMLEDGER_HISTORY_SIZE=100 #only useful when use ram ledger - ORDERER_GENERAL_TLS_ENABLED=${FABKIT_TLS_ENABLED} # default: false @@ -66,9 +68,14 @@ services: - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] - expose: - - "7050" # gRPC - - "8443" # Operation REST + - ORDERER_CHANNELPARTICIPATION_ENABLED=true + - ORDERER_ADMIN_TLS_ENABLED=${FABKIT_TLS_ENABLED} + - ORDERER_ADMIN_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt + - ORDERER_ADMIN_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key + - ORDERER_ADMIN_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] + - ORDERER_ADMIN_TLS_CLIENTROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] + - ORDERER_ADMIN_LISTENADDRESS=0.0.0.0:7053 + - ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:17050 working_dir: /opt/gopath/src/github.com/hyperledger/fabric #command: bash -c 'bash /tmp/orderer_build.sh; orderer start' # use this if to debug orderer command: orderer start @@ -78,6 +85,7 @@ services: environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_TLS_ENABLED=${FABKIT_TLS_ENABLED} + - FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:17054 command: sh -c 'fabric-ca-server start --ca.certfile `ls /etc/hyperledger/fabric-ca-server-config/*.pem` --ca.keyfile `ls /etc/hyperledger/fabric-ca-server-config/*_sk` -b admin:adminpw -d' tools-base: diff --git a/network/org1.yaml b/network/org1.yaml index c515d18..0b337d3 100644 --- a/network/org1.yaml +++ b/network/org1.yaml @@ -2,9 +2,8 @@ version: "2.4" networks: default: - external: - # This value should be the same for fabric network and client - name: ${FABKIT_DOCKER_NETWORK} + # This value should be the same for fabric network and client + name: ${FABKIT_DOCKER_NETWORK} volumes: orderer.example.com: @@ -32,6 +31,8 @@ services: - orderer.example.com:/var/hyperledger/production/orderer ports: - 7050:7050 + - 7053:7053 + - 17050:17050 ca.org1.example.com: container_name: ca.org1.example.com @@ -40,11 +41,13 @@ services: service: ca-base environment: - FABRIC_CA_SERVER_CA_NAME=ca.org1.example.com + - FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:17054 volumes: - ${FABKIT_HOST_ROOT}/network/cryptos/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config - ca.org1.example.com:/etc/hyperledger/fabric-ca-server ports: - 7054:7054 + - 17054:17054 peer0.org1.example.com: container_name: peer0.org1.example.com @@ -62,8 +65,10 @@ services: - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP + - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:17051 - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_LEDGER_STATE_STATEDATABASE=CouchDB - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb.peer0.org1.example.com:5984 @@ -75,6 +80,7 @@ services: - peer0.org1.example.com:/var/hyperledger/production ports: - 7051:7051 + - 17051:17051 depends_on: - couchdb.peer0.org1.example.com diff --git a/network/org2.yaml b/network/org2.yaml index 381f735..7394b48 100644 --- a/network/org2.yaml +++ b/network/org2.yaml @@ -2,9 +2,8 @@ version: "2.4" networks: default: - external: - # This value should be the same for fabric network and client - name: ${FABKIT_DOCKER_NETWORK} + # This value should be the same for fabric network and client + name: ${FABKIT_DOCKER_NETWORK} volumes: ca.org2.example.com: @@ -22,11 +21,13 @@ services: service: ca-base environment: - FABRIC_CA_SERVER_CA_NAME=ca.org2.example.com + - FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:18054 volumes: - ${FABKIT_HOST_ROOT}/network/cryptos/peerOrganizations/org2.example.com/ca/:/etc/hyperledger/fabric-ca-server-config - ca.org2.example.com:/etc/hyperledger/fabric-ca-server ports: - 8054:7054 + - 18054:18054 peer0.org2.example.com: container_name: peer0.org2.example.com @@ -41,8 +42,10 @@ services: - CORE_PEER_LISTENADDRESS=0.0.0.0:8051 - CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:8052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:8052 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:8051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:8051 - CORE_PEER_LOCALMSPID=Org2MSP + - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:18051 - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_LEDGER_STATE_STATEDATABASE=CouchDB - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb.peer0.org2.example.com:5984 @@ -54,6 +57,7 @@ services: - peer0.org2.example.com:/var/hyperledger/production ports: - 8051:8051 + - 18051:18051 depends_on: - couchdb.peer0.org2.example.com diff --git a/network/org3.yaml b/network/org3.yaml index 1cc02f7..3efea97 100644 --- a/network/org3.yaml +++ b/network/org3.yaml @@ -2,9 +2,8 @@ version: "2.4" networks: default: - external: - # This value should be the same for fabric network and client - name: ${FABKIT_DOCKER_NETWORK} + # This value should be the same for fabric network and client + name: ${FABKIT_DOCKER_NETWORK} volumes: ca.org3.example.com: @@ -22,11 +21,13 @@ services: service: ca-base environment: - FABRIC_CA_SERVER_CA_NAME=ca.org3.example.com + - FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:19054 volumes: - ${FABKIT_HOST_ROOT}/network/cryptos/peerOrganizations/org3.example.com/ca/:/etc/hyperledger/fabric-ca-server-config - ca.org3.example.com:/etc/hyperledger/fabric-ca-server ports: - 9054:7054 + - 19054:19054 peer0.org3.example.com: container_name: peer0.org3.example.com @@ -41,8 +42,10 @@ services: - CORE_PEER_LISTENADDRESS=0.0.0.0:9051 - CORE_PEER_CHAINCODEADDRESS=peer0.org3.example.com:9052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org3.example.com:9051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org3.example.com:9051 - CORE_PEER_LOCALMSPID=Org3MSP + - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:19051 - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_LEDGER_STATE_STATEDATABASE=CouchDB - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb.peer0.org3.example.com:5984 @@ -54,6 +57,7 @@ services: - peer0.org3.example.com:/var/hyperledger/production ports: - 9051:9051 + - 19051:19051 depends_on: - couchdb.peer0.org3.example.com diff --git a/scripts/channel.sh b/scripts/channel.sh index e4186ed..8ce22a9 100644 --- a/scripts/channel.sh +++ b/scripts/channel.sh @@ -17,7 +17,7 @@ init_and_create_channel() { generate_channeltx "$channel_name" "$FABKIT_NETWORK_PATH" "$FABKIT_CONFIG_PATH" "$FABKIT_CRYPTOS_PATH" "$FABKIT_CONFIGTX_PROFILE_NETWORK" "$FABKIT_CONFIGTX_PROFILE_CHANNEL" "$msp_id" __spinner_formatter - create_channel $@ + create_channel "$@" } create_channel() { diff --git a/scripts/console.sh b/scripts/console.sh new file mode 100644 index 0000000..5b7be67 --- /dev/null +++ b/scripts/console.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +start_console() { + loginfoln "Starting console" + + if ! docker ps | grep -q "fabric"; then + logerr "No Fabric networks running. First launch fabkit start" + exit 1 + fi + + if [ ! -d "${FABKIT_CRYPTOS_PATH}" ]; then + logerr "Cryptos path ${FABKIT_CRYPTOS_PATH} does not exist." + exit 1 + fi + + (stop_console) & + __spinner + + ( + if loginfo "Launching Console components" && docker-compose --env-file "${FABKIT_ROOT}/.env" -f "${FABKIT_CONSOLE_PATH}/docker-compose.yaml" up --force-recreate -d 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Failed to launch containers" + exit 1 + fi + ) & + __spinner + + __generate_assets + + echo "Blockchain Console default user is admin/password - $(logsucc http://localhost:3000)" +} + +stop_console() { + loginfo "Stopping console" + + if docker-compose --env-file "${FABKIT_ROOT}/.env" -f "${FABKIT_CONSOLE_PATH}/docker-compose.yaml" down 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Failed to stop containers" + exit 1 + fi + docker volume rm -f $(docker volume ls | awk '($2 ~ /console/) {print $2}') &>/dev/null || true +} + +__generate_assets() { + local assets_path="${FABKIT_CONSOLE_PATH}/assets" + local templates_path="${FABKIT_CONSOLE_PATH}/templates" + local assets_file="${FABKIT_DIST_PATH}/console_assets.zip" + + rm -rf "${assets_path}" &>/dev/null + mkdir -p "${assets_path}/Certificate_Authorities" + mkdir -p "${assets_path}/Ordering_Services" + mkdir -p "${assets_path}/Peers" + mkdir -p "${assets_path}/Organizations" + + local orderer_root_cert="" + for org in $(seq 1 "${FABKIT_ORGS}"); do + # extract org root cert from ca info + local org_root_cert=$(curl -sk http"$(if [ "${FABKIT_TLS_ENABLED:-}" = "true" ]; then echo "s"; fi)"://localhost:$((6 + org))054/cainfo | __run "$FABKIT_ROOT" jq -r .result.CAChain) + + # create org ca import + if ( + (__run "$FABKIT_ROOT" jq --arg org_root_cert "$org_root_cert" "'.tls_cert = \"$org_root_cert\" | .msp.ca.root_certs[0] = \"$org_root_cert\"'" "${templates_path}/Certificate_Authorities/orgca-local_ca.json" >"${assets_path}/Certificate_Authorities/org${org}ca-local_ca.json") && + sed -i'.bak' -e "s/%ORG%/${org}/g" -e "s/%PORT_INDEX%/$((6 + org))/g" "${assets_path}/Certificate_Authorities/org${org}ca-local_ca.json" && rm "${assets_path}/Certificate_Authorities/org${org}ca-local_ca.json.bak" &>/dev/null + ) 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Error creating org${org} ca import" + exit 1 + fi + + # TODO: repeat for number of peers + # create peer import + if ( + (__run "$FABKIT_ROOT" jq --arg org_root_cert "$org_root_cert" \ + "'.msp.component.tls_cert = \"$org_root_cert\" | .msp.ca.root_certs[0] = \"$org_root_cert\" | .msp.tlsca.root_certs[0] = \"$org_root_cert\" | .pem = \"$org_root_cert\" | .tls_cert = \"$org_root_cert\" | .tls_ca_root_cert = \"$org_root_cert\"'" \ + "${templates_path}/Peers/org_peer-local_peer.json" >"${assets_path}/Peers/org${org}_peer0-local_peer.json") && + sed -i'.bak' -e "s/%ORG%/${org}/g" -e "s/%PORT_INDEX%/$((6 + org))/g" "${assets_path}/Peers/org${org}_peer0-local_peer.json" && rm "${assets_path}/Peers/org${org}_peer0-local_peer.json.bak" &>/dev/null + ) 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Error creating org${org} peer import" + exit 1 + fi + + # create org msp import + if ( + (__run "$FABKIT_ROOT" jq --arg org_root_cert "$org_root_cert" \ + "'.root_certs[0] = \"$org_root_cert\" | .tls_root_certs[0] = \"$org_root_cert\" | .fabric_node_ous.admin_ou_identifier.certificate = \"$org_root_cert\" | .fabric_node_ous.client_ou_identifier.certificate = \"$org_root_cert\" | .fabric_node_ous.orderer_ou_identifier.certificate = \"$org_root_cert\" | .fabric_node_ous.peer_ou_identifier.certificate = \"$org_root_cert\"'" \ + "${templates_path}/Organizations/orgmsp_msp.json" >"${assets_path}/Organizations/org${org}msp_msp.json") && + sed -i'.bak' -e "s/%ORG%/${org}/g" "${assets_path}/Organizations/org${org}msp_msp.json" && rm "${assets_path}/Organizations/org${org}msp_msp.json.bak" &>/dev/null + ) 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Error creating org${org} msp import" + exit 1 + fi + + if [ "${org}" -eq 1 ]; then + orderer_root_cert=$org_root_cert + + # TODO: if an orderer ca msp is defined, retrieve its root certificate with curl pointing to the right address + # local orderer_root_cert=$(curl -sk http"$(if [ "${FABKIT_TLS_ENABLED:-}" = "true" ]; then echo "s"; fi)"://localhost:$((6 + org))$((0 + org))54/cainfo | __run "$FABKIT_ROOT" jq -r .result.CAChain) + + # create orderer ca import + # if (__run "$FABKIT_ROOT" jq --arg orderer_root_cert "$orderer_root_cert" "'.tls_cert = \"$orderer_root_cert\"'" "${templates_path}/Certificate_Authorities/ordererca-local_ca.json" >"${assets_path}/Certificate_Authorities/ordererca-local_ca.json") 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + # logerr "Error creating orderer ca import" + # exit 1 + # fi + + # create orderers import + if (__run "$FABKIT_ROOT" jq --arg orderer_root_cert "$orderer_root_cert" \ + "'.msp.component.tls_cert = \"$orderer_root_cert\" | .msp.ca.root_certs[0] = \"$orderer_root_cert\" | .msp.tlsca.root_certs[0] = \"$orderer_root_cert\" | .pem = \"$orderer_root_cert\" | .tls_cert = \"$orderer_root_cert\" | .tls_ca_root_cert = \"$orderer_root_cert\"'" \ + "${templates_path}/Ordering_Services/orderer-local_orderer.json" >"${assets_path}/Ordering_Services/orderer-local_orderer.json") 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Error creating orderers import" + exit 1 + fi + + # create orderer msp import + if (__run "$FABKIT_ROOT" jq --arg orderer_root_cert "$orderer_root_cert" \ + "'.root_certs[0] = \"$orderer_root_cert\" | .tls_root_certs[0] = \"$orderer_root_cert\" | .fabric_node_ous.admin_ou_identifier.certificate = \"$orderer_root_cert\" | .fabric_node_ous.client_ou_identifier.certificate = \"$orderer_root_cert\" | .fabric_node_ous.orderer_ou_identifier.certificate = \"$orderer_root_cert\" | .fabric_node_ous.peer_ou_identifier.certificate = \"$orderer_root_cert\"'" \ + "${templates_path}/Organizations/orderermsp_msp.json" >"${assets_path}/Organizations/orderermsp_msp.json") 2>&1 >/dev/null | grep -iE "erro|pani|fail|fatal" > >(__throw >&2); then + logerr "Error creating orderer msp import" + exit 1 + fi + fi + done + + cd "${assets_path}" && rm -rf "${assets_file}" &>/dev/null && zip -rq "${assets_file}" . +} diff --git a/scripts/explorer.sh b/scripts/explorer.sh index dd5ea67..1060056 100644 --- a/scripts/explorer.sh +++ b/scripts/explorer.sh @@ -40,7 +40,7 @@ start_explorer() { __spinner echo "Blockchain Explorer default user is exploreradmin/exploreradminpw - $(logsucc http://localhost:8090)" - echo "Grafana default user is admin/admin - $(logsucc http://localhost:3000)" + echo "Grafana default user is admin/admin - $(logsucc http://localhost:3333)" } stop_explorer() { @@ -50,5 +50,5 @@ stop_explorer() { logerr "Failed to stop containers" exit 1 fi - docker volume prune -f $(docker volume ls | awk '($2 ~ /explorer/) {print $2}') &>/dev/null || true + docker volume rm -f $(docker volume ls | awk '($2 ~ /explorer/) {print $2}') &>/dev/null || true } diff --git a/scripts/helpers.sh b/scripts/helpers.sh index 5bfe81d..fd8c65a 100644 --- a/scripts/helpers.sh +++ b/scripts/helpers.sh @@ -30,6 +30,7 @@ help() { help_ca help_network help_explorer + help_console help_channel help_generate help_chaincode @@ -78,6 +79,14 @@ help_explorer() { " } +help_console() { + help_header "fabkit console" + loginfo " + start : run the blockchain console user-interface + stop : stop the blockchain console user-interface + " +} + help_channel() { help_header "fabkit channel" loginfo " diff --git a/scripts/network.sh b/scripts/network.sh index 802fb65..a3ec335 100644 --- a/scripts/network.sh +++ b/scripts/network.sh @@ -115,7 +115,7 @@ restart_network() { } __prune_docker_volumes() { - docker volume prune -f $(docker volume ls | awk '($2 ~ /${FABKIT_DOCKER_NETWORK}/) {print $2}') &>/dev/null + docker volume rm -f $(docker volume ls | awk -v network="$FABKIT_DOCKER_NETWORK" '($2 ~ network) {print $2}') &>/dev/null || true } __check_docker_volumes() { @@ -175,9 +175,15 @@ stop_network() { stop_explorer fi + if docker ps | grep -q "fabric-console"; then + echo -en "\n\033[3C→ " + stop_console + fi + __clear_logdebu logdebu "Cleaning docker leftovers containers and images" - docker rm -f $(docker ps -a | awk '($2 ~ /${FABKIT_DOCKER_NETWORK}|dev-/) {print $1}') &>/dev/null || true + docker rm -f $(docker ps -a | awk -v network="$FABKIT_DOCKER_NETWORK" '($2 ~ network) {print $1}') &>/dev/null || true + docker rm -f $(docker ps -a | awk '($2 ~ /dev-/) {print $1}') &>/dev/null || true docker rmi -f $(docker images -qf "dangling=true") &>/dev/null || true docker rmi -f $(docker images | awk '($1 ~ /^|dev-/) {print $3}') &>/dev/null || true }