DevOps in Oracle Blockchain Platform
Published: 2022-01-24 00:51:09

#Intro

[Oracle Blockchain Platform](https://docs.oracle.com/en/cloud/paas/blockchain-cloud/index.html) is built on top of the [HyperLedger Fabric](https://hlf.readthedocs.io/en/latest/).
It provides additional capabilities like web administration console, Oracle Berkley DB, with SQL syntax support, as World State, improved transaction validation and, what we will focus in this post on, set of REST APIs in front of native fabric GRPC APIs.

REST APIs cover things like: 

- chaincode installation, approval, committing
- chaincode invocation
- updating configuration of nodes (peer, ca, orderer)
- checking node health, etc. (full list of APIs is available here: [API documentation](https://docs.oracle.com/en/cloud/paas/blockchain-cloud/restoci/index.html))

# Goal

Let's use said REST APIs to rapidly automate daily devops tasks. To that end we need a CLI that we can use easily in our CI/CD pipelines or to perform ad-hoc tasks.

# Implementation

## Step 1

First, we need to go to OBP web console and download swagger file with all REST APIs definitions.

![OBP UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrh2n5y6fu6hxrerofj4.png)

## Step 2 

Now, we need to generate REST client from a swagger spec file. It will be "golang" client in my case so I will use [go-swagger](https://github.com/go-swagger/go-swagger) tool.

`./swagger generate client  -f OBP_swagger.yml -A obp-admin`

where:

- "OBP_swagger.yml" - name of a swagger file
- "obp-admin" - arbitrary client name

Generated code is ready to be used straight away. It contains "golang" structures that define requests/responses for respective APIs and "client" package that orchestrates all HTTP communication.  

## Step 3

We can start to implement calls to REST APIs. Let's make a call to [Get Installed Chaincode List](https://docs.oracle.com/en/cloud/paas/blockchain-cloud/restoci/op-console-admin-api-v2-chaincodes-get.html) endpoint as an example.

**Note:** Below code uses "cobra" as a library to create CLI application, but of course it't not a requirement. 

```golang
var ListChaincodesCmd = &cobra.Command{
	Use:   "list",
	Short: "Get a list of installed chaincodes, optionally for a given peer.",
	Run: func(cmd *cobra.Command, args []string) {

		//set basic authentication header (user + password)
		auth := runtimeClient.BasicAuth(cmd.Flag("user").Value.String(), cmd.Flag("passwd").Value.String())

		//set URL to OBP
		config := client.DefaultTransportConfig().WithHost(cmd.Flag("obpHost").Value.String())

		//create client
		cl := client.NewHTTPClientWithConfig(strfmt.Default, config)

		//optionally take id of a peer
		peerId := cmd.Flag("peerId").Value.String()
		
		//make a call to REST API, parse the response
		resp, err := cl.Chaincode.GetInstalledChaincodes(chaincode.NewGetInstalledChaincodesParams().WithPeerID(&peerId), auth)
		if err != nil {
			logger.Fatalf("Unexpected error:%v", err)
		}

		//display the response (list of chaincodes)
		aJSON, _ := json.MarshalIndent(resp.GetPayload(), "", "\t")
		fmt.Printf("\n%v \n", string(aJSON))
	},
}
```

# Summary

Using swagger spec we can implement devops CLI tool for OBP rapidly. 

A few practical things to keep in mind:

- in case of failure (for example: due to bad input parameters) the response from the server can be very vague - HTTP code without any further information. It's good then to check the server logs, usually they are very descriptive.
- sometimes, changes to autogenerated code are needed. One example is, when "bool" parameter in API request is required, but is marked as "omitempty" in autogenerated code - we need to remove "omitempty" tag then (otherwise, if parameter is set to "false", it will be omitted from the request payload which will result in an error).