Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dviejokfs committed Feb 19, 2024
0 parents commit 1275cf2
Show file tree
Hide file tree
Showing 215 changed files with 51,496 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
Empty file added LICENSE
Empty file.
126 changes: 126 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# HLF Easy

HLF Easy is a tool to simplify the process of setting up Hyperledger Fabric nodes. It is designed to be used in baremetal environment.

![Easy HLF.png](./docs/images/Easy%20HLF.png)

# Tutorial

### Pre requisites
- HLF Peer binaries
- HLF Orderer binaries



### Install fabric binaries

```bash
curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh
./install-fabric.sh 2.5.5
```

### Compile the code
```bash
go build -o hlf-easy ./main.go && sudo mv hlf-easy /usr/local/bin/hlf-easy
```

### Follow the HLF meetup 2024

Complete the meetup 2024 to get a running network with 2 peer organizations and 1 orderer organization.

Repository: https://github.com/kfsoftware/meetup-k8s-hlf-2024

Youtube: https://www.youtube.com/watch?v=8qPXaRzrFiQ

### Init the certificate authority

After initializing the certificate authority, you can inspect the certificate authority to get the certificates.

All the certificates will be saved in $HOME/hlf-easy with a custom structure.

```bash

hlf-easy ca init --hosts=192.168.1.36 --hosts localhost --hosts 127.0.0.1 --hosts ca.localho.st --name=ca-1

hlf-easy ca inspect --name=ca-1 > localorg1-ca.yaml

```

### Initializing the peer certificates

Once we have the certificates generated we need to initialize the peer certificates.

First, we need to find our external IP address, this is the IP address that the network nodes will use to connect to the peer.

You can use `ifconfig` or `ip a` to find the IP address of the interface that is connected to the network.
```bash
export EXTERNAL_HOST=192.168.1.36
```

And then, we can initialize the peer certificates.
```bash
hlf-easy peer init --hosts=${EXTERNAL_HOST} --hosts localhost --hosts 127.0.0.1 --hosts peer01.localho.st --ca-name=ca-1 --id=peer1 --local=true

hlf-easy peer init --hosts=${EXTERNAL_HOST} --hosts localhost --hosts 127.0.0.1 --hosts peer02.localho.st --ca-name=ca-1 --id=peer2 --local=true
```

### Starting the peers

```bash

hlf-easy peer start --id=peer1 --msp-id=LocalOrg1 --external-endpoint="${EXTERNAL_HOST}:7051" \
--listen-address="0.0.0.0:7051" \
--chaincode-address="0.0.0.0:7052" \
--events-address="0.0.0.0:7053" \
--operations-listen-address="0.0.0.0:7054" \
--mgmt-address="0.0.0.0:7055"


hlf-easy peer start --id=peer2 --msp-id=LocalOrg1 --external-endpoint="${EXTERNAL_HOST}:7061" \
--listen-address="0.0.0.0:7061" \
--chaincode-address="0.0.0.0:7062" \
--events-address="0.0.0.0:7063" \
--operations-listen-address="0.0.0.0:7064" \
--mgmt-address="0.0.0.0:7065"
```
### Enroll the admin and client

After the peer is started, we can enroll the admin and client using our local ca
```bash

hlf-easy ca enroll --name=ca-1 --local=true --type=admin --common-name=admin > peer-admin.yaml

hlf-easy ca enroll --name=ca-1 --local=true --type=client --common-name=client > peer-client.yaml
```

### Joining a network

Once the peer is started and the admin is enrolled, we can join the peer to a network, for this, we need to have a running network, the variables to get the orderer certificate and the URLs are based on the 2024 HLF workshop mentioned above.

```bash

kubectl get fabricorderernodes ord-node1 -o=jsonpath='{.status.tlsCert}' | sed -e "s/^/${IDENT_8}/" > orderer0-tls.pem

hlf-easy peer join --id=peer1 --channel=demo2 --identity=peer-admin.yaml --orderer-url=grpcs://orderer0-ord.localho.st:443 --orderer-tls-cert=orderer0-tls.pem

hlf-easy peer join --id=peer2 --channel=demo2 --identity=peer-admin.yaml --orderer-url=grpcs://orderer0-ord.localho.st:443 --orderer-tls-cert=orderer0-tls.pem
```
### Setting the anchor peers
```bash
hlf-easy peer anchorpeers set --id=peer1 --channel=demo2 --identity=peer-admin.yaml \
--orderer-url=grpcs://orderer0-ord.localho.st:443 --orderer-tls-cert=orderer0-tls.pem \
--anchor-peers="${EXTERNAL_HOST}:7051" --anchor-peers="${EXTERNAL_HOST}:7061"



```

## Roadmap

- [ ] Enroll using Fabric CA instead of local CA
- [ ] Docs for setting up and joining orderers
- [ ] Admin UI for Peer
- [ ] Add detail of the peer + process stats (CPU, memory, requests)
- [ ] Add logs
- [ ] Add chaincode support
- [ ] Add operations: restart, stop, start, upgrade, certificate renewal
218 changes: 218 additions & 0 deletions api/orderer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package api

import (
"embed"
"encoding/json"
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/hyperledger/fabric-lib-go/healthz"
"github.com/hyperledger/fabric/core/operations"
"hlf-easy/config"
"hlf-easy/node"
"hlf-easy/ui"
"io/ioutil"
"net/http"
"os"
"path/filepath"
)

type OrdererClient struct {
OperationsAddress string
OrdererAddress string
}

func (pc *OrdererClient) GetVersionInfo() (*operations.VersionInfoHandler, error) {
resp, err := http.Get(pc.OperationsAddress + "/version")
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
versionInfo := &operations.VersionInfoHandler{}
err = json.Unmarshal(body, versionInfo)
if err != nil {
return nil, err
}
return versionInfo, nil
}

func (pc *OrdererClient) GetHealthz() (*healthz.HealthStatus, error) {
resp, err := http.Get(pc.OperationsAddress + "/healthz")
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
healthInfo := &healthz.HealthStatus{}
err = json.Unmarshal(body, healthInfo)
if err != nil {
return nil, err
}
return healthInfo, nil
}

func getHandlerFuncForOrdererFile(opts config.StartOrdererOpts, filename string) func(c *gin.Context) {
return func(c *gin.Context) {
contents, err := os.ReadFile(filepath.Join(opts.MSPConfigPath, filename))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"contents": string(contents),
})
}
}

func NewOrdererRouter(
node *node.OrdererNode,
cmdOrdererStdout *config.SaveOutputWriter,
cmdOrdererStderr *config.SaveOutputWriter,
startOptions config.OrdererStartOptions,
opts config.StartOrdererOpts,
views embed.FS,
) (*gin.Engine, error) {
r := gin.Default()
peerClient := &OrdererClient{
OperationsAddress: fmt.Sprintf("http://%s", startOptions.OperationsListenAddress),
OrdererAddress: startOptions.ListenAddress,
}
config := cors.DefaultConfig()
config.AllowAllOrigins = true // Allow all origins
config.AllowMethods = []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"} // Specify what methods are allowed
config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type"}

r.Use(cors.New(config))
r.GET("/tls.crt", getHandlerFuncForOrdererFile(opts, "tls.crt"))
r.GET("/tlscacert.crt", getHandlerFuncForOrdererFile(opts, "tlscacerts/cacert.pem"))
r.GET("/cacert.crt", getHandlerFuncForOrdererFile(opts, "cacerts/cacert.pem"))
r.GET("/sign.crt", getHandlerFuncForOrdererFile(opts, "signcerts/cert.pem"))
r.GET("/core.yaml", getHandlerFuncForOrdererFile(opts, "core.yaml"))
r.POST("/restart", func(context *gin.Context) {
err := node.Stop()
if err != nil {
context.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
err = node.Start()
if err != nil {
context.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"success": true,
})
})
r.POST("/stop", func(context *gin.Context) {
err := node.Stop()
if err != nil {
context.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"success": true,
})
})
r.POST("/start", func(context *gin.Context) {
err := node.Start()
if err != nil {
context.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"success": true,
})
})
r.GET("/status", func(context *gin.Context) {
status, err := node.Status()
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, status)
})
r.GET("/config", func(c *gin.Context) {
conf, err := node.GetConfig()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
status, err := node.Status()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
version, err := peerClient.GetVersionInfo()
if err != nil {
// return generic error in this gin route
version = &operations.VersionInfoHandler{
Version: "unknown",
CommitSHA: "unknown",
}
}
c.JSON(http.StatusOK, gin.H{
"config": conf,
"status": status,
"version": version,
"startOptions": startOptions,
})
})
r.GET("/logs", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"stdout": string(cmdOrdererStdout.GetSavedOutput()),
"stderr": string(cmdOrdererStderr.GetSavedOutput()),
})
})
fileSystem := ui.NewFileSystemUI(views, "web")

r.GET("/healthz", func(c *gin.Context) {
version, err := peerClient.GetHealthz()
if err != nil {
// return generic error in this gin route
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, version)
})

r.GET("/version", func(c *gin.Context) {
version, err := peerClient.GetVersionInfo()
if err != nil {
// return generic error in this gin route
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, version)
})
r.Use(static.Serve("/", fileSystem))
r.NoRoute(ReturnPublic(views))
return r, nil
}
Loading

0 comments on commit 1275cf2

Please sign in to comment.