Skip to content

Commit

Permalink
chore: add upgrade plan fetcher and generator
Browse files Browse the repository at this point in the history
  • Loading branch information
freak12techno committed Sep 9, 2024
1 parent 03072e0 commit 573cd72
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 102 deletions.
1 change: 1 addition & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
FetcherNameAppVersion FetcherName = "app_version"
FetcherNameRemoteVersion FetcherName = "remote_version"
FetcherNameLocalVersion FetcherName = "local_version"
FetcherNameUpgrades FetcherName = "upgrades"
)

var (
Expand Down
56 changes: 56 additions & 0 deletions pkg/fetchers/upgrades_fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package fetchers

import (
"context"
"main/pkg/clients/tendermint"
"main/pkg/constants"
"main/pkg/query_info"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

"github.com/rs/zerolog"
)

type UpgradesFetcher struct {
TendermintRPC *tendermint.RPC
Logger zerolog.Logger
Tracer trace.Tracer
}

func NewUpgradesFetcher(logger zerolog.Logger, tendermintRPC *tendermint.RPC, tracer trace.Tracer) *UpgradesFetcher {
return &UpgradesFetcher{
Logger: logger.With().Str("component", "upgrades_fetcher").Logger(),
TendermintRPC: tendermintRPC,
Tracer: tracer,
}
}

func (n *UpgradesFetcher) Enabled() bool {
return n.TendermintRPC != nil
}

func (n *UpgradesFetcher) Name() constants.FetcherName {
return constants.FetcherNameUpgrades
}

func (n *UpgradesFetcher) Dependencies() []constants.FetcherName {
return []constants.FetcherName{}
}

func (n *UpgradesFetcher) Get(ctx context.Context) (interface{}, []query_info.QueryInfo) {
childCtx, span := n.Tracer.Start(
ctx,
"Fetcher "+string(n.Name()),
trace.WithAttributes(attribute.String("node", n.TendermintRPC.Address)),
)
defer span.End()

upgradePlan, queryInfo, err := n.TendermintRPC.GetUpgradePlan(childCtx)
if err != nil {
n.Logger.Error().Err(err).Msg("Could not fetch upgrade plan")
return nil, []query_info.QueryInfo{queryInfo}
}

return upgradePlan, []query_info.QueryInfo{queryInfo}
}
78 changes: 78 additions & 0 deletions pkg/fetchers/upgrades_fetcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package fetchers

import (
"context"
"errors"
"main/assets"
"main/pkg/clients/tendermint"
configPkg "main/pkg/config"
"main/pkg/constants"
loggerPkg "main/pkg/logger"
"main/pkg/tracing"
"testing"

"github.com/jarcoal/httpmock"

"github.com/stretchr/testify/assert"
)

func TestUpgradesFetcherBase(t *testing.T) {
t.Parallel()

config := configPkg.TendermintConfig{
Address: "https://example.com",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewUpgradesFetcher(*logger, client, tracer)
assert.True(t, fetcher.Enabled())
assert.Equal(t, constants.FetcherNameUpgrades, fetcher.Name())
assert.Empty(t, fetcher.Dependencies())
}

//nolint:paralleltest // disabled due to httpmock usage
func TestUpgradesFetcherFail(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder(
"GET",
"https://example.com/abci_query?path=%22%2Fcosmos.upgrade.v1beta1.Query%2FCurrentPlan%22&data=0x",
httpmock.NewErrorResponder(errors.New("custom error")),
)

config := configPkg.TendermintConfig{Address: "https://example.com"}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewUpgradesFetcher(*logger, client, tracer)

data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.False(t, queryInfos[0].Success)
assert.Nil(t, data)
}

//nolint:paralleltest // disabled due to httpmock usage
func TestUpgradesFetcherOk(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder(
"GET",
"https://example.com/abci_query?path=%22%2Fcosmos.upgrade.v1beta1.Query%2FCurrentPlan%22&data=0x",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("upgrade-plan.json")),
)

config := configPkg.TendermintConfig{Address: "https://example.com"}
logger := loggerPkg.GetDefaultLogger()
tracer := tracing.InitNoopTracer()
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := NewUpgradesFetcher(*logger, client, tracer)

data, queryInfos := fetcher.Get(context.Background())
assert.Len(t, queryInfos, 1)
assert.True(t, queryInfos[0].Success)
assert.NotNil(t, data)
}
40 changes: 40 additions & 0 deletions pkg/generators/upgrades_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package generators

import (
"main/pkg/constants"
"main/pkg/fetchers"
"main/pkg/metrics"

upgradeTypes "cosmossdk.io/x/upgrade/types"
)

type UpgradesGenerator struct{}

func NewUpgradesGenerator() *UpgradesGenerator {
return &UpgradesGenerator{}
}

func (g *UpgradesGenerator) Get(state fetchers.State) []metrics.MetricInfo {
upgradesRaw, ok := state[constants.FetcherNameUpgrades]
if !ok || upgradesRaw == nil {
return []metrics.MetricInfo{}
}

upgradeInfo, ok := upgradesRaw.(*upgradeTypes.Plan)
if !ok {
panic("expected the state entry to be string")
}

return []metrics.MetricInfo{
{
MetricName: metrics.MetricNameUpgradeInfo,
Labels: map[string]string{"name": upgradeInfo.Name, "info": upgradeInfo.Info},
Value: 1,
},
{
MetricName: metrics.MetricNameUpgradeHeight,
Labels: map[string]string{"name": upgradeInfo.Name},
Value: float64(upgradeInfo.Height),
},
}
}
87 changes: 87 additions & 0 deletions pkg/generators/upgrades_generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package generators

import (
"context"
"main/assets"
"main/pkg/clients/tendermint"
configPkg "main/pkg/config"
"main/pkg/constants"
"main/pkg/fetchers"
loggerPkg "main/pkg/logger"
"main/pkg/tracing"
"testing"

"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/require"

"github.com/stretchr/testify/assert"
)

func TestUpgradesGeneratorEmpty(t *testing.T) {
t.Parallel()

state := fetchers.State{}

generator := NewUpgradesGenerator()

metrics := generator.Get(state)
assert.Empty(t, metrics)
}

func TestUpgradesGeneratorInvalid(t *testing.T) {
t.Parallel()

defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

state := fetchers.State{
constants.FetcherNameUpgrades: 3,
}

generator := NewUpgradesGenerator()
generator.Get(state)
}

//nolint:paralleltest // disabled due to httpmock usage
func TestUpgradesGeneratorOk(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder(
"GET",
"https://example.com/abci_query?path=%22%2Fcosmos.upgrade.v1beta1.Query%2FCurrentPlan%22&data=0x",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("upgrade-plan.json")),
)

config := configPkg.TendermintConfig{
Address: "https://example.com",
}
logger := loggerPkg.GetNopLogger()
tracer := tracing.InitNoopTracer()
client := tendermint.NewRPC(config, *logger, tracer)
fetcher := fetchers.NewUpgradesFetcher(*logger, client, tracer)

data, _ := fetcher.Get(context.Background())
assert.NotNil(t, data)

state := fetchers.State{
constants.FetcherNameUpgrades: data,
}

generator := NewUpgradesGenerator()

metrics := generator.Get(state)
assert.Len(t, metrics, 2)

upgradeInfo := metrics[0]
assert.NotEmpty(t, upgradeInfo.Labels["info"])
assert.Equal(t, "v1.5.0", upgradeInfo.Labels["name"])
assert.InDelta(t, 1, upgradeInfo.Value, 0.01)

upgradeHeight := metrics[1]
assert.Equal(t, "v1.5.0", upgradeHeight.Labels["name"])
assert.InDelta(t, 8375044, upgradeHeight.Value, 0.01)
}
14 changes: 3 additions & 11 deletions pkg/metrics/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,6 @@ func NewManager() *Manager {
[]string{"node", "local_version", "remote_version"},
),

MetricNameUpgradeComing: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: constants.MetricsPrefix + "upgrade_coming",
Help: "Is future upgrade planned?",
},
[]string{"node"},
),

MetricNameUpgradeInfo: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: constants.MetricsPrefix + "upgrade_info",
Expand All @@ -107,23 +99,23 @@ func NewManager() *Manager {
Name: constants.MetricsPrefix + "upgrade_height",
Help: "Future upgrade height",
},
[]string{"node", "name", "info"},
[]string{"node", "name"},
),

MetricNameUpgradeEstimatedTime: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: constants.MetricsPrefix + "upgrade_estimated_time",
Help: "Estimated upgrade time, as Unix timestamp",
},
[]string{"node", "name", "info"},
[]string{"node", "name"},
),

MetricNameUpgradeBinaryPresent: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: constants.MetricsPrefix + "upgrade_binary_present",
Help: "Is upgrade binary present?",
},
[]string{"node", "name", "info"},
[]string{"node", "name"},
),

MetricNameQuerierEnabled: prometheus.NewGaugeVec(
Expand Down
1 change: 0 additions & 1 deletion pkg/metrics/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const (
MetricNameRemoteVersion MetricName = "remote_version"
MetricNameLocalVersion MetricName = "local_version"
MetricNameIsLatest MetricName = "is_latest"
MetricNameUpgradeComing MetricName = "upgrade_coming"
MetricNameUpgradeInfo MetricName = "upgrade_info"
MetricNameUpgradeHeight MetricName = "upgrade_height"
MetricNameUpgradeEstimatedTime MetricName = "upgrade_estimated_time"
Expand Down
2 changes: 2 additions & 0 deletions pkg/node_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func NewNodeHandler(
fetchersPkg.NewNodeInfoFetcher(appLogger, grpc, tracer),
fetchersPkg.NewRemoteVersionFetcher(appLogger, gitClient, tracer),
fetchersPkg.NewLocalVersionFetcher(appLogger, cosmovisor, tracer),
fetchersPkg.NewUpgradesFetcher(appLogger, tendermintRPC, tracer),
}

generators := []generatorsPkg.Generator{
Expand All @@ -80,6 +81,7 @@ func NewNodeHandler(
generatorsPkg.NewRemoteVersionGenerator(),
generatorsPkg.NewLocalVersionGenerator(),
generatorsPkg.NewIsLatestGenerator(appLogger),
generatorsPkg.NewUpgradesGenerator(),
}

controller := fetchersPkg.NewController(fetchers, appLogger, config.Name)
Expand Down
20 changes: 3 additions & 17 deletions pkg/queriers/upgrades/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,13 @@ func (u *Querier) Get(ctx context.Context) ([]metrics.MetricInfo, []query_info.Q

isUpgradePresent := upgrade != nil

metricInfos := []metrics.MetricInfo{{
MetricName: metrics.MetricNameUpgradeComing,
Labels: map[string]string{},
Value: utils.BoolToFloat64(isUpgradePresent),
}}
metricInfos := []metrics.MetricInfo{}
queryInfos := []query_info.QueryInfo{upgradePlanQuery}

if !isUpgradePresent {
return metricInfos, queryInfos
}

metricInfos = append(metricInfos, metrics.MetricInfo{
MetricName: metrics.MetricNameUpgradeInfo,
Labels: map[string]string{"name": upgrade.Name, "info": upgrade.Info},
Value: utils.BoolToFloat64(isUpgradePresent),
}, metrics.MetricInfo{
MetricName: metrics.MetricNameUpgradeHeight,
Labels: map[string]string{"name": upgrade.Name, "info": upgrade.Info},
Value: float64(upgrade.Height),
})

// Calculate upgrade estimated time
upgradeTime, upgradeTimeQuery, err := u.Tendermint.GetEstimateBlockTime(childCtx, upgrade.Height)
queryInfos = append(queryInfos, upgradeTimeQuery)
Expand All @@ -96,7 +82,7 @@ func (u *Querier) Get(ctx context.Context) ([]metrics.MetricInfo, []query_info.Q

metricInfos = append(metricInfos, metrics.MetricInfo{
MetricName: metrics.MetricNameUpgradeEstimatedTime,
Labels: map[string]string{"name": upgrade.Name, "info": upgrade.Info},
Labels: map[string]string{"name": upgrade.Name},
Value: float64(upgradeTime.Unix()),
})

Expand All @@ -123,7 +109,7 @@ func (u *Querier) Get(ctx context.Context) ([]metrics.MetricInfo, []query_info.Q

metricInfos = append(metricInfos, metrics.MetricInfo{
MetricName: metrics.MetricNameUpgradeBinaryPresent,
Labels: map[string]string{"name": upgrade.Name, "info": upgrade.Info},
Labels: map[string]string{"name": upgrade.Name},
Value: utils.BoolToFloat64(upgrades.HasUpgrade(upgradeName)),
})

Expand Down
Loading

0 comments on commit 573cd72

Please sign in to comment.