Skip to content

Commit

Permalink
Add initial code for collector service (#30)
Browse files Browse the repository at this point in the history
* Add initial code for collector service

* update makefile to change name

* Adding fileserver to read and write from files

* Add ability to store snapshots in the file servers

* Add snapshot and export capabilities for collector service

* Fix collector code

* Add collector service and add prestop lifecycle hook to register snapshots

* Update gas for hermes

* update version of chart
  • Loading branch information
Anmol1696 authored Dec 23, 2022
1 parent b35f3f3 commit 0ab82cf
Show file tree
Hide file tree
Showing 20 changed files with 1,062 additions and 5 deletions.
2 changes: 1 addition & 1 deletion charts/devnet/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.10
version: 0.1.11

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
Expand Down
24 changes: 24 additions & 0 deletions charts/devnet/scripts/register_snapshots.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

CHAIN_ID="${CHAIN_ID:=osmosis-1}"
VAL_NAME="${VAL_NAME:=osmosis}"
CHAIN_DIR="${CHAIN_DIR:=$HOME/.osmosisd}"
COLLECTOR_HOST="${COLLECTOR_HOST}"

set -euxo pipefail

snapshot_name=data_${VAL_NAME}_$(date "+%F-%H-%M-%S")

# Create the snapshot that will be uploaded
function create_snapshot {
tar -czvf /opt/${snapshot_name}.tar.gz $CHAIN_DIR/data
}

# Register the snapshot to the collector service
function register_snapshot {
url=${COLLECTOR_HOST}/chains/${CHAIN_ID}/validators/${VAL_NAME}/snapshots/${snapshot_name}.tar.gz
curl -v -i ${url} -H'Content-Encoding: gzip' -H'Content-TYPE: application/gzip' --data-binary @/opt/${snapshot_name}.tar.gz
}

create_snapshot
register_snapshot
22 changes: 22 additions & 0 deletions charts/devnet/templates/chain/genesis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ spec:
env:
{{- include "devnet.defaultEvnVars" $defaultChain | indent 12 }}
{{- include "devnet.evnVars" $chain | indent 12 }}
- name: COLLECTOR_SERVICE
value: collector
- name: COLLECTOR_PORT
value: "8070"
command:
- bash
- "-c"
Expand All @@ -124,6 +128,24 @@ spec:
name: node
- mountPath: /configs
name: addresses
- mountPath: /scripts
name: scripts
{{- if $.Values.collector.enabled }}
lifecycle:
preStop:
exec:
command:
- bash
- "-c"
- "-e"
- |
VAL_INDEX=${HOSTNAME##*-}
VAL_NAME=$(jq -r ".genesis[$VAL_INDEX].name" /configs/keys.json)
echo "Validator Index: $VAL_INDEX, Key name: $VAL_NAME"
COLLECTOR_HOST=http://$COLLECTOR_SERVICE.$NAMESPACE.svc.cluster.local:$COLLECTOR_PORT
VAL_NAME=$VAL_NAME COLLECTOR_HOST=$COLLECTOR_HOST bash -e /scripts/register_snapshots.sh
{{- end }}
- name: exposer
image: {{ $.Values.exposer.image }}
imagePullPolicy: Always
Expand Down
19 changes: 19 additions & 0 deletions charts/devnet/templates/chain/validator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ spec:
{{- include "devnet.defaultEvnVars" $defaultChain | indent 12 }}
{{- include "devnet.evnVars" $chain | indent 12 }}
{{- include "devnet.genesisVars" $dataExposer | indent 12}}
- name: COLLECTOR_SERVICE
value: collector
- name: COLLECTOR_PORT
value: "8070"
command:
- bash
- "-c"
Expand All @@ -158,6 +162,21 @@ spec:
$CHAIN_BIN keys list | jq
VAL_NAME=$VAL_NAME bash -e /scripts/create_validator.sh
{{- if $.Values.collector.enabled }}
preStop:
exec:
command:
- bash
- "-c"
- "-e"
- |
VAL_INDEX=${HOSTNAME##*-}
VAL_NAME=$(jq -r ".validators[$VAL_INDEX].name" /configs/keys.json)
echo "Validator Index: $VAL_INDEX, Key name: $VAL_NAME"
COLLECTOR_HOST=http://$COLLECTOR_SERVICE.$NAMESPACE.svc.cluster.local:$COLLECTOR_PORT
VAL_NAME=$VAL_NAME COLLECTOR_HOST=$COLLECTOR_HOST bash -e /scripts/register_snapshots.sh
{{- end }}
resources: {{- include "devnet.validator.resources" $chain | trim | nindent 12 }}
volumeMounts:
- mountPath: {{ $defaultChain.home }}
Expand Down
77 changes: 77 additions & 0 deletions charts/devnet/templates/collector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{{- if .Values.collector.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: collector
labels:
app.kubernetes.io/name: collector
spec:
clusterIP: None
ports:
- name: collector
port: 8070
protocol: TCP
targetPort: 8070
selector:
app.kubernetes.io/name: collector
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: collector
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/instance: collector
app.kubernetes.io/name: collector
template:
metadata:
annotations:
quality: release
role: api-gateway
sla: high
tier: gateway
labels:
app.kubernetes.io/instance: collector
app.kubernetes.io/type: collector
app.kubernetes.io/name: collector
app.kubernetes.io/version: {{ $.Chart.AppVersion }}
spec:
containers:
- name: collector
image: {{ .Values.collector.image }}
imagePullPolicy: Always
env:
- name: COLLECTOR_ADDR
value: ":8070"
- name: COLLECTOR_DIR_PATH
value: /opt/collector
command: [ "collector" ]
resources:
limits:
cpu: "1"
memory: 4Gi
requests:
cpu: "0.5"
memory: 2Gi
volumeMounts:
- mountPath: /opt/collector
name: collector
readinessProbe:
tcpSocket:
port: 8070
initialDelaySeconds: 60
periodSeconds: 30
livenessProbe:
tcpSocket:
port: 8070
initialDelaySeconds: 60
periodSeconds: 30
volumes:
- name: collector
emptyDir: {}
---
{{- end }}
6 changes: 3 additions & 3 deletions charts/devnet/templates/relayers/hermes/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ data:
websocket_addr = "ws://{{ $chain }}-genesis.{{ $.Release.Namespace }}.svc.cluster.local:26657/websocket"
{{- with index $.Values.defaultChains $fullchain.type }}
account_prefix = "{{ .prefix }}"
gas_price = { price = 0.025, denom = "{{ .denom }}" }
gas_price = { price = 0.25, denom = "{{ .denom }}" }
{{- end }}
default_gas = 50000000
max_gas = 100000000
default_gas = 500000000
max_gas = 1000000000
rpc_timeout = "10s"
store_prefix = "ibc"
gas_multiplier = 1.5
Expand Down
7 changes: 7 additions & 0 deletions charts/devnet/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,10 @@ chainRegistry:
image: anmol1696/chain-registry
ports:
rest: 8090

collector:
enabled: false
image: anmol1696/collector:latest
localhost: true
ports:
rest: 8070
27 changes: 27 additions & 0 deletions collector/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM golang:1.19-alpine AS build-env

# Set up dependencies
ENV PACKAGES curl make git libc-dev bash gcc linux-headers

# Set working directory for the build
WORKDIR /usr/local/share/app

# Add source files
COPY . .

# Install minimum necessary dependencies, build Cosmos SDK, remove packages
RUN apk add --no-cache $PACKAGES && go build -mod readonly -o collector ./...

# Final image
FROM alpine:3.16

# Install ca-certificates
RUN apk add --update ca-certificates jq bash curl
WORKDIR /usr/local/share/app

RUN ls /usr/bin

# Copy over binaries from the build-env
COPY --from=build-env /usr/local/share/app/collector /usr/bin/collector

EXPOSE 8081
16 changes: 16 additions & 0 deletions collector/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
DOCKER := $(shell which docker)
DOCKER_REPO_NAME := anmol1696
DOCKER_IMAGE := collector
DOCKER_TAG_NAME := latest

DOCKER_ARGS += --platform linux/amd64

docker-build:
$(DOCKER) buildx build $(DOCKER_ARGS) \
-t $(DOCKER_REPO_NAME)/$(DOCKER_IMAGE):$(DOCKER_TAG_NAME) .

docker-build-push: docker-build
$(DOCKER) push $(DOCKER_REPO_NAME)/$(DOCKER_IMAGE):$(DOCKER_TAG_NAME)

docker-run:
$(DOCKER) run --rm -it --entrypoint /bin/bash $(DOCKER_REPO_NAME)/$(DOCKER_IMAGE):$(DOCKER_TAG_NAME)
134 changes: 134 additions & 0 deletions collector/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package main

import (
"fmt"
"net/http"
"time"

"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/render"
"go.uber.org/zap"
)

type AppServer struct {
config *Config
db *FileDB
logger *zap.Logger
server *http.Server
router http.Handler
}

func NewAppServer(config *Config) (*AppServer, error) {
log, err := NewLogger(config)
if err != nil {
return nil, err
}
log.Info(
"Starting the service",
zap.String("prog", Prog),
zap.String("version", Version),
zap.Any("config", config),
)

app := &AppServer{
config: config,
logger: log,
db: NewFileDB(log, config.DirPath),
}

// Setup routes
router, err := app.Router()
if err != nil {
log.Error("Error setting up routes", zap.Error(err))
return nil, err
}
app.router = router

return app, err
}

func (a *AppServer) Router() (*chi.Mux, error) {
router := chi.NewRouter()
router.MethodNotAllowed(MethodNotAllowed)
router.NotFound(NotFound)

// Set middleware
router.Use(a.panicRecovery)
router.Use(render.SetContentType(render.ContentTypeJSON))

// Setup routes
// handler of export states
router.Get("/chains", a.GetChains)
router.Route("/chains/{chain}/validators/{validator}", func(r chi.Router) {
r.Get("/exports", a.GetChainExports)
r.Get("/exports/{id}", a.GetChainExport)
r.Post("/exports/{id}", a.SetChainExport)
r.Get("/snapshots", a.GetChainSnapshots)
r.Get("/snapshots/{id}", a.GetChainSnapshot)
r.Post("/snapshots/{id}", a.SetChainSnapshot)
})

return router, nil
}

func (a *AppServer) loggingMiddleware(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
start := time.Now()
defer func() {
a.logger.Info("client request",
zap.Duration("latency", time.Since(start)),
zap.Int("status", ww.Status()),
zap.Int("bytes", ww.BytesWritten()),
zap.String("client_ip", r.RemoteAddr),
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("request-id", middleware.GetReqID(r.Context())))
}()

next.ServeHTTP(ww, r)
}
return http.HandlerFunc(fn)
}

func (a *AppServer) panicRecovery(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rc := recover(); rc != nil {
err, ok := rc.(error)
if !ok {
err = fmt.Errorf("panic: %v", rc)
}
a.logger.Error("panic error",
zap.String("request-id", middleware.GetReqID(r.Context())),
zap.Error(err))

render.Render(w, r, ErrInternalServer)
return
}
}()
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}

func (a *AppServer) Run() error {
a.logger.Info("App starting", zap.Any("Config", a.config))

// Setup server
server := &http.Server{
Addr: a.config.Addr,
Handler: a.router,
}
a.server = server

// Start http server as long-running go routine
go func() {
if err := server.ListenAndServe(); err != nil {
a.logger.Error("failed to start the App HTTP server", zap.Error(err))
}
}()

return nil
}
Loading

0 comments on commit 0ab82cf

Please sign in to comment.