Skip to content

Commit

Permalink
feat: add modular Git clients support (#24)
Browse files Browse the repository at this point in the history
* feat: add modular Git clients support

* chore: remove fossa
  • Loading branch information
freak12techno authored Nov 10, 2023
1 parent 33cce9a commit 9c4fcdb
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 56 deletions.
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

![Latest release](https://img.shields.io/github/v/release/QuokkaStake/cosmos-node-exporter)
[![Actions Status](https://github.com/QuokkaStake/cosmos-node-exporter/workflows/test/badge.svg)](https://github.com/QuokkaStake/cosmos-node-exporter/actions)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-node-exporter.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-node-exporter?ref=badge_shield)

cosmos-node-exporter is a Prometheus scraper that scrapes some data to monitor your node, specifically you can set up alerting if:
- your app version does not match the latest on GitHub (can be useful to be notified on new releases)
Expand Down Expand Up @@ -110,7 +109,3 @@ All configuration is done via `.toml` config. Check config.example.toml for refe
## How can I contribute?

Bug reports and feature requests are always welcome! If you want to contribute, feel free to open issues or PRs.


## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-node-exporter.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FQuokkaStake%2Fcosmos-node-exporter?ref=badge_large)
9 changes: 3 additions & 6 deletions pkg/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"main/pkg/config"
"main/pkg/constants"
cosmovisorPkg "main/pkg/cosmovisor"
githubPkg "main/pkg/github"
git "main/pkg/git"
"main/pkg/queriers/app"
cosmovisorQuerierPkg "main/pkg/queriers/cosmovisor"
nodeStats "main/pkg/queriers/node_stats"
Expand Down Expand Up @@ -39,7 +39,6 @@ func NewApp(

var tendermintRPC *tendermint.RPC
var cosmovisor *cosmovisorPkg.Cosmovisor
var github *githubPkg.Github

if config.TendermintConfig.Enabled.Bool {
tendermintRPC = tendermint.NewRPC(config, logger)
Expand All @@ -49,13 +48,11 @@ func NewApp(
cosmovisor = cosmovisorPkg.NewCosmovisor(config, logger)
}

if config.GithubConfig.Repository != "" {
github = githubPkg.NewGithub(config, logger)
}
gitClient := git.GetClient(config, logger)

queriers := []types.Querier{
nodeStats.NewQuerier(logger, tendermintRPC),
versions.NewQuerier(logger, github, cosmovisor),
versions.NewQuerier(logger, gitClient, cosmovisor),
upgrades.NewQuerier(config, logger, cosmovisor, tendermintRPC),
cosmovisorQuerierPkg.NewQuerier(logger, cosmovisor),
app.NewQuerier(version),
Expand Down
8 changes: 4 additions & 4 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type TendermintConfig struct {
QueryUpgrades null.Bool `default:"true" toml:"query-upgrades"`
}

type GithubConfig struct {
type GitConfig struct {
Repository string `default:"" toml:"repository"`
Token string `toml:"token"`
}
Expand Down Expand Up @@ -57,11 +57,11 @@ type Config struct {
LogConfig LogConfig `toml:"log"`
TendermintConfig TendermintConfig `toml:"tendermint"`
CosmovisorConfig CosmovisorConfig `toml:"cosmovisor"`
GithubConfig GithubConfig `toml:"github"`
GitConfig GitConfig `toml:"git"`
ListenAddress string `default:":9500" toml:"listen-address"`
}

func (c *GithubConfig) Validate() error {
func (c *GitConfig) Validate() error {
if c.Repository == "" {
return nil
}
Expand All @@ -74,7 +74,7 @@ func (c *GithubConfig) Validate() error {
}

func (c *Config) Validate() error {
if err := c.GithubConfig.Validate(); err != nil {
if err := c.GitConfig.Validate(); err != nil {
return fmt.Errorf("GitHub config is invalid: %s", err)
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (

const (
MetricsPrefix = "cosmos_node_exporter_"
UncachedGithubQueryTime = time.Hour
UncachedGithubQueryTime = 30 * time.Second
)

var (
GithubRegexp = regexp.MustCompile("https://github.com/(?P<Org>[a-zA-Z0-9-].*)/(?P<Repo>[a-zA-Z0-9-].*)")
GithubRegexp = regexp.MustCompile("https://github.com/(?P<Org>[a-zA-Z0-9-].*)/(?P<Repo>[a-zA-Z0-9-].*)")
GitopiaRegexp = regexp.MustCompile("gitopia://(?P<Org>[a-zA-Z0-9-].*)/(?P<Repo>[a-zA-Z0-9-].*)")
)
19 changes: 19 additions & 0 deletions pkg/git/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package git

import (
configPkg "main/pkg/config"

"github.com/rs/zerolog"
)

type Client interface {
GetLatestRelease() (string, error)
}

func GetClient(config *configPkg.Config, logger *zerolog.Logger) Client {
if config.GitConfig.Repository != "" {
return NewGithub(config, logger)
}

return nil
}
32 changes: 16 additions & 16 deletions pkg/github/github.go → pkg/git/github.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package github
package git

import (
"encoding/json"
Expand All @@ -18,24 +18,25 @@ type Github struct {
Token string
Logger zerolog.Logger
LastModified time.Time
LastResult *types.ReleaseInfo
LastResult string
}

func NewGithub(config *config.Config, logger *zerolog.Logger) *Github {
value := constants.GithubRegexp.FindStringSubmatch(config.GithubConfig.Repository)
value := constants.GithubRegexp.FindStringSubmatch(config.GitConfig.Repository)

return &Github{
Organization: value[1],
Repository: value[2],
Token: config.GithubConfig.Token,
Logger: logger.With().Str("component", "github").Logger(),
Token: config.GitConfig.Token,
Logger: logger.With().Str("component", "git").Logger(),
LastModified: time.Now(),
LastResult: "",
}
}

func (g *Github) UseCache() bool {
// If the last result is not present - do not use cache, for the first query.
if g.LastResult == nil {
if g.LastResult == "" {
return false
}

Expand All @@ -45,7 +46,7 @@ func (g *Github) UseCache() bool {
return diff < constants.UncachedGithubQueryTime
}

func (g *Github) GetLatestRelease() (types.ReleaseInfo, error) {
func (g *Github) GetLatestRelease() (string, error) {
latestReleaseUrl := fmt.Sprintf(
"https://api.github.com/repos/%s/%s/releases/latest",
g.Organization,
Expand All @@ -58,7 +59,7 @@ func (g *Github) GetLatestRelease() (types.ReleaseInfo, error) {

req, err := http.NewRequest(http.MethodGet, latestReleaseUrl, nil)
if err != nil {
return types.ReleaseInfo{}, err
return "", err
}

useCache := g.UseCache()
Expand All @@ -80,30 +81,29 @@ func (g *Github) GetLatestRelease() (types.ReleaseInfo, error) {

res, err := client.Do(req)
if err != nil {
return types.ReleaseInfo{}, err
return "", err
}
defer res.Body.Close()

if res.StatusCode == http.StatusNotModified && g.LastResult != nil {
if res.StatusCode == http.StatusNotModified && g.LastResult != "" {
g.Logger.Trace().Msg("Github returned cached response")
g.LastModified = time.Now()
return *g.LastResult, nil
return g.LastResult, nil
}

releaseInfo := types.ReleaseInfo{}
err = json.NewDecoder(res.Body).Decode(&releaseInfo)

if err != nil {
return releaseInfo, err
return "", err
}

// GitHub returned error, probably rate-limiting
if releaseInfo.Message != "" {
return releaseInfo, fmt.Errorf("got error from Github: %s", releaseInfo.Message)
return "", fmt.Errorf("got error from Github: %s", releaseInfo.Message)
}

g.LastModified = time.Now()
g.LastResult = &releaseInfo
g.LastResult = releaseInfo.TagName

return releaseInfo, err
return releaseInfo.TagName, err
}
41 changes: 18 additions & 23 deletions pkg/queriers/versions/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package versions
import (
"main/pkg/constants"
cosmovisorPkg "main/pkg/cosmovisor"
"main/pkg/github"
"main/pkg/git"
"main/pkg/query_info"
"main/pkg/types"
"main/pkg/utils"
Expand All @@ -16,24 +16,24 @@ import (

type Querier struct {
Logger zerolog.Logger
Github *github.Github
GitClient git.Client
Cosmovisor *cosmovisorPkg.Cosmovisor
}

func NewQuerier(
logger *zerolog.Logger,
github *github.Github,
gitClient git.Client,
cosmovisor *cosmovisorPkg.Cosmovisor,
) *Querier {
return &Querier{
Logger: logger.With().Str("component", "versions_querier").Logger(),
Github: github,
GitClient: gitClient,
Cosmovisor: cosmovisor,
}
}

func (v *Querier) Enabled() bool {
return v.Github != nil || v.Cosmovisor != nil
return v.GitClient != nil || v.Cosmovisor != nil
}

func (v *Querier) Name() string {
Expand All @@ -45,32 +45,27 @@ func (v *Querier) Get() ([]prometheus.Collector, []query_info.QueryInfo) {
collectors := []prometheus.Collector{}

var (
releaseInfo types.ReleaseInfo
versionInfo types.VersionInfo
err error
latestVersion string
versionInfo types.VersionInfo
err error
)

if v.Github != nil {
if v.GitClient != nil {
queriesInfo = append(queriesInfo, query_info.QueryInfo{
Module: "github",
Module: "git",
Action: "get_latest_release",
Success: false,
})

releaseInfo, err = v.Github.GetLatestRelease()
latestVersion, err = v.GitClient.GetLatestRelease()
if err != nil {
v.Logger.Err(err).Msg("Could not get latest Github version")
return []prometheus.Collector{}, queriesInfo
}

if releaseInfo.TagName == "" {
v.Logger.Err(err).Msg("Malformed Github response when querying version")
v.Logger.Err(err).Msg("Could not get latest Git version")
return []prometheus.Collector{}, queriesInfo
}

// stripping first "v" character: "v1.2.3" => "1.2.3"
if releaseInfo.TagName[0] == 'v' {
releaseInfo.TagName = releaseInfo.TagName[1:]
if latestVersion[0] == 'v' {
latestVersion = latestVersion[1:]
}

queriesInfo[len(queriesInfo)-1].Success = true
Expand All @@ -84,7 +79,7 @@ func (v *Querier) Get() ([]prometheus.Collector, []query_info.QueryInfo) {
)

remoteVersion.
With(prometheus.Labels{"version": releaseInfo.TagName}).
With(prometheus.Labels{"version": latestVersion}).
Set(1)

collectors = append(collectors, remoteVersion)
Expand Down Expand Up @@ -120,14 +115,14 @@ func (v *Querier) Get() ([]prometheus.Collector, []query_info.QueryInfo) {
collectors = append(collectors, localVersion)
}

if v.Github != nil && v.Cosmovisor != nil {
if v.GitClient != nil && v.Cosmovisor != nil {
semverLocal, err := semver.NewVersion(versionInfo.Version)
if err != nil {
v.Logger.Err(err).Msg("Could not get local app version")
return collectors, queriesInfo
}

semverRemote, err := semver.NewVersion(releaseInfo.TagName)
semverRemote, err := semver.NewVersion(latestVersion)
if err != nil {
v.Logger.Err(err).Msg("Could not get remote app version")
return collectors, queriesInfo
Expand All @@ -147,7 +142,7 @@ func (v *Querier) Get() ([]prometheus.Collector, []query_info.QueryInfo) {
isUsingLatestVersion.
With(prometheus.Labels{
"local_version": versionInfo.Version,
"remote_version": releaseInfo.TagName,
"remote_version": latestVersion,
}).
Set(utils.BoolToFloat64(isLatestOrSameVersion))

Expand Down

0 comments on commit 9c4fcdb

Please sign in to comment.