diff --git a/Dockerfile b/Dockerfile index b4bbb70..22d2714 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20.3-bullseye AS builder +FROM golang:1.21.0-bullseye AS builder WORKDIR / COPY go.mod go.sum ./ # Download dependencies diff --git a/Dockerfile_local b/Dockerfile_local index d61e6bc..f568cd4 100644 --- a/Dockerfile_local +++ b/Dockerfile_local @@ -1,4 +1,4 @@ -FROM golang:1.20.3-bullseye AS builder +FROM golang:1.21.0-bullseye AS builder WORKDIR / COPY go.mod go.sum ./ # Download dependencies diff --git a/Makefile b/Makefile index 13f5de0..bd2c39a 100644 --- a/Makefile +++ b/Makefile @@ -69,4 +69,4 @@ kubectl_deploy: docker_build_local_push kubectl_apply .PHYONY: kubectl_deploy kubectl_remote_kustomize_deploy: docker_build_local_push_gh kubectl_kustomize -.PHYONY: kubectl_remote_kustomize_deploy \ No newline at end of file +.PHYONY: kubectl_remote_kustomize_deploys \ No newline at end of file diff --git a/config/config.go b/config/config.go index 1156923..cbf1352 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,7 @@ type MutualPeersConfig struct { // MutualPeer represents a mutual peer structure. type MutualPeer struct { + ConsensusNode string `yaml:"consensusNode,omitempty"` // List of peers. Peers []Peer `yaml:"peers"` TrustedPeersPath string `yaml:"trustedPeersPath,omitempty"` diff --git a/deployment/overlays/local/config/config.yaml b/deployment/overlays/local/config/config.yaml index 54815c7..5cfe98e 100644 --- a/deployment/overlays/local/config/config.yaml +++ b/deployment/overlays/local/config/config.yaml @@ -1,4 +1,5 @@ mutualPeers: + - consensusNode: "consensus-validator-1" - peers: - nodeName: "da-bridge-1-0" containerName: "da" diff --git a/pkg/http/server.go b/pkg/http/server.go index 7850619..80f58d9 100644 --- a/pkg/http/server.go +++ b/pkg/http/server.go @@ -62,6 +62,22 @@ func Run(cfg config.MutualPeersConfig) { return } + // Get the genesisHash + // check if the config has the consensusNode field defined + if cfg.MutualPeers[0].ConsensusNode != "" { + blockHash, earliestBlockTime := k8s.GenesisHash(cfg) + err = metrics.WithMetricsBlockHeight( + blockHash, + earliestBlockTime, + cfg.MutualPeers[0].ConsensusNode, + os.Getenv("POD_NAMESPACE"), + ) + if err != nil { + log.Errorf("Error registering metric block_height_1: %v", err) + return + } + } + // Create the server server := &http.Server{ Addr: ":" + httpPort, diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 5404ba5..a32d716 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -3,7 +3,11 @@ package k8s import ( "bytes" "context" + "encoding/json" "errors" + "fmt" + "io/ioutil" + "net/http" "os" "sync" @@ -274,6 +278,61 @@ func BulkTrustedPeers(pods config.MutualPeer) { } } +// GenesisHash +func GenesisHash(pods config.MutualPeersConfig) (string, string) { + consensusNode := pods.MutualPeers[0].ConsensusNode + url := fmt.Sprintf("http://%s:26657/block?height=1", consensusNode) + + response, err := http.Get(url) + if err != nil { + log.Error("Error making GET request:", err) + return "", "" + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + log.Error("Non-OK response:", response.Status) + return "", "" + } + + bodyBytes, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Error("Error reading response body:", err) + return "", "" + } + + bodyString := string(bodyBytes) + log.Info("Response Body:", bodyString) + + // Parse the JSON response into a generic map + var jsonResponse map[string]interface{} + err = json.Unmarshal([]byte(bodyString), &jsonResponse) + if err != nil { + log.Error("Error parsing JSON:", err) + return "", "" + } + + // Access and print the .block_id.hash field + blockIDHash, ok := jsonResponse["result"].(map[string]interface{})["block_id"].(map[string]interface{})["hash"].(string) + if !ok { + log.Error("Unable to access .block_id.hash") + return "", "" + } + + // Access and print the .block.header.time field + blockTime, ok := jsonResponse["result"].(map[string]interface{})["block"].(map[string]interface{})["header"].(map[string]interface{})["time"].(string) + if !ok { + log.Error("Unable to access .block.header.time") + return "", "" + } + + log.Info("Block ID Hash: ", blockIDHash) + log.Info("Block Time: ", blockTime) + log.Info("Full output: ", bodyString) + + return blockIDHash, blockTime +} + // RunRemoteCommand executes a remote command on the specified node. func RunRemoteCommand(nodeName, container, namespace string, command []string) (string, error) { clusterConfig, err := rest.InClusterConfig() diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 247db10..e82ea51 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -2,6 +2,8 @@ package metrics import ( "context" + "fmt" + "time" log "github.com/sirupsen/logrus" @@ -11,7 +13,7 @@ import ( ) // Get the meter from the global meter provider with the name "torch". -var meter = otel.GetMeterProvider().Meter("multiaddr") +var meter = otel.GetMeterProvider().Meter("torch") // MultiAddrs represents the information for a multiaddress. type MultiAddrs struct { @@ -56,3 +58,59 @@ func WithMetricsMultiAddress(multiAddrs []MultiAddrs) error { _, err = meter.RegisterCallback(callback, multiAddressesGauge) return err } + +// BlockHeight represents the information for the block height 1. +type BlockHeight struct { + ServiceName string // ServiceName Name of the service associated with the multiaddress. + BlockHeight string // Namespace where the service is deployed. + Value float64 // Value to be observed for the multiaddress. +} + +// WithMetricsBlockHeight creates a callback function to observe metrics for block_height_1. +// consensus-node:26657/block?height=1 +func WithMetricsBlockHeight(blockHeight, earliestBlockTime, serviceName, namespace string) error { + log.Info("registering metric: ", blockHeight) + // Create a Float64ObservableGauge named "block_height_1" with a description for the metric. + blockHeightGauge, err := meter.Float64ObservableGauge( + "block_height_1", + metric.WithDescription("Torch - BlockHeight"), + ) + if err != nil { + log.Fatalf(err.Error()) + return err + } + callback := func(ctx context.Context, observer metric.Observer) error { + // Define the callback function that will be called periodically to observe metrics. + // Create labels with attributes for each block_height_1. + labels := metric.WithAttributes( + attribute.String("service_name", serviceName), + attribute.String("block_height_1", blockHeight), + attribute.String("earliest_block_time", earliestBlockTime), + attribute.Int("days_running", CalculateDaysDifference(earliestBlockTime)), + attribute.String("namespace", namespace), + ) + // Observe the float64 value for the current block_height_1 with the associated labels. + observer.ObserveFloat64(blockHeightGauge, 1, labels) + + return nil + } + + // Register the callback with the meter and the Float64ObservableGauge. + _, err = meter.RegisterCallback(callback, blockHeightGauge) + return err +} + +func CalculateDaysDifference(inputTimeString string) int { + layout := "2006-01-02T15:04:05.999999999Z" + inputTime, err := time.Parse(layout, inputTimeString) + if err != nil { + fmt.Println("Error parsing time:", err) + return -1 + } + + currentTime := time.Now() + timeDifference := currentTime.Sub(inputTime) + daysDifference := int(timeDifference.Hours() / 24) + + return daysDifference +}