Skip to content

Commit

Permalink
Merge pull request #1 from snapp-incubator/initial-dev
Browse files Browse the repository at this point in the history
Basic Code Implementation: Initial Branch
  • Loading branch information
kianaza authored May 19, 2024
2 parents 5b9399c + fdff66e commit 25f8c9e
Show file tree
Hide file tree
Showing 15 changed files with 831 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: ci
on:
- push
jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: latest
test:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: 1.22
- run: go test -v ./... -covermode=atomic -coverprofile=coverage.out
- uses: codecov/codecov-action@v1
with:
files: coverage.out
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# golang
.idea/

# config
config.yaml
27 changes: 27 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ---
# linters:
# enable-all: true
# disable:
# - depguard
# # we don't use json with camel-case
# - tagliatelle
# - nolintlint
# # it should improve to support more known patterns
# - varnamelen
# - ireturn
# # deprecated linters
# - maligned
# - scopelint
# - golint
# - ifshort
# - interfacer
# - exhaustivestruct
# - nosnakecase
# - varcheck
# - deadcode
# - structcheck
# - gomnd
# - execinquery
# # temporarily disabled
# - tagalign
# - gochecknoglobals
26 changes: 26 additions & 0 deletions build/package/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Start from the latest golang base image
FROM golang:alpine AS builder

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source from the current directory to the Working Directory inside the container
COPY . .

# Build the Go app
WORKDIR /app/cmd/nats-blackbox-exporter
RUN go build -o /nats-blackbox-exporter

FROM alpine:latest

WORKDIR /app/

COPY --from=builder /nats-blackbox-exporter .

ENTRYPOINT ["./nats-blackbox-exporter"]
7 changes: 7 additions & 0 deletions cmd/nats-blackbox-exporter/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/snapp-incubator/nats-blackbox-exporter/internal/cmd"

func main() {
cmd.Execute()
}
30 changes: 30 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module github.com/snapp-incubator/nats-blackbox-exporter

go 1.22.0

require (
github.com/knadh/koanf v1.5.0
github.com/knadh/koanf/v2 v2.1.1
github.com/nats-io/nats.go v1.31.0
github.com/spf13/cobra v1.8.0
github.com/tidwall/pretty v1.2.1
go.uber.org/zap v1.17.0
)

require (
github.com/fatih/structs v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/nats-io/nkeys v0.4.5 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/sys v0.5.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
410 changes: 410 additions & 0 deletions go.sum

Large diffs are not rendered by default.

Binary file added internal/.DS_Store
Binary file not shown.
87 changes: 87 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package client

import (
"time"

"github.com/nats-io/nats.go"
"go.uber.org/zap"
)

type Client struct {
Conn *nats.Conn
Logger *zap.Logger
Config Config
}

func Connect(logger *zap.Logger, cfg Config) *nats.Conn {
nc, err := nats.Connect(cfg.URL)
if err != nil {
logger.Fatal("nats connection failed", zap.Error(err))
}

logger.Info("nats connection successful",
zap.String("connected-addr", nc.ConnectedAddr()),
zap.Strings("discovered-servers", nc.DiscoveredServers()))

nc.SetDisconnectErrHandler(func(_ *nats.Conn, err error) {
logger.Fatal("nats disconnected", zap.Error(err))
})

nc.SetReconnectHandler(func(_ *nats.Conn) {
logger.Warn("nats reconnected")
})

return nc
}

func New(nc *nats.Conn, logger *zap.Logger, cfg Config) *Client {
return &Client{
Conn: nc,
Logger: logger,
Config: cfg,
}
}

func (c *Client) StartMessaging() {
go c.Subscribe("")
go c.Publish("")
}

func (c *Client) Publish(subject string) {
if subject == "" {
subject = c.Config.DefaultSubject
}
for {
msg, err := c.Conn.Request(subject, []byte("Hello, NATS!"), c.Config.RequestTimeout)
if err != nil {
if err == nats.ErrTimeout {
c.Logger.Error("Request timeout: No response received within the timeout period.")
} else if err == nats.ErrNoResponders {
c.Logger.Error("Request failed: No responders available for the subject.")
} else {
c.Logger.Error("Request failed: %v", zap.Error(err))
}
} else {
c.Logger.Info("Received response successfully:", zap.ByteString("response", msg.Data))
}

time.Sleep(c.Config.PublishInterval)
}
}

func (c *Client) Subscribe(subject string) {
if subject == "" {
subject = c.Config.DefaultSubject
}
_, err := c.Conn.Subscribe(subject, func(msg *nats.Msg) {
c.Logger.Info("Received message successfully: ", zap.ByteString("message", msg.Data))
err := c.Conn.Publish(msg.Reply, []byte("Hi!"))
if err != nil {
c.Logger.Error("Failed to publish response: %v", zap.Error(err))
}
})
if err != nil {
c.Logger.Error("Failed to subscribe to subject 'subject1': %v", zap.Error(err))
}

}
10 changes: 10 additions & 0 deletions internal/client/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package client

import "time"

type Config struct {
URL string `json:"url,omitempty" koanf:"url"`
PublishInterval time.Duration `json:"publish_interval" koanf:"publish_interval"`
RequestTimeout time.Duration `json:"request_timeout" koanf:"request_timeout"`
DefaultSubject string `json:"default_subject" koanf:"default_subject"`
}
25 changes: 25 additions & 0 deletions internal/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cmd

import (
"os"
"os/signal"
"syscall"

"github.com/snapp-incubator/nats-blackbox-exporter/internal/client"
"github.com/snapp-incubator/nats-blackbox-exporter/internal/config"
"go.uber.org/zap"
)

func main(cfg config.Config, logger *zap.Logger) {
natsConfig := cfg.NATS

natsClient := client.New(client.Connect(logger, natsConfig), logger, natsConfig)

natsClient.StartMessaging()

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
logger.Info("Received termination signal. Exiting...")
os.Exit(0)
}
31 changes: 31 additions & 0 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cmd

import (
"os"

"github.com/snapp-incubator/nats-blackbox-exporter/internal/config"
"github.com/snapp-incubator/nats-blackbox-exporter/internal/logger"
"github.com/spf13/cobra"
)

// ExitFailure status code.
const ExitFailure = 1

func Execute() {
cfg := config.New()

logger := logger.New(cfg.Logger)

// nolint: exhaustruct
root := &cobra.Command{
Use: "nats-blackbox-exporter",
Short: "ping pong with nats broker",
Run: func(_ *cobra.Command, _ []string) {
main(cfg, logger)
},
}

if err := root.Execute(); err != nil {
os.Exit(ExitFailure)
}
}
73 changes: 73 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package config

import (
"encoding/json"
"log"
"strings"

"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/providers/structs"
"github.com/knadh/koanf/v2"
"github.com/snapp-incubator/nats-blackbox-exporter/internal/client"
"github.com/snapp-incubator/nats-blackbox-exporter/internal/logger"
"github.com/tidwall/pretty"
)

const (
// Prefix indicates environment variables prefix.
Prefix = "nbe_"
)

type (
// Config holds all configurations.
Config struct {
Logger logger.Config `json:"logger,omitempty" koanf:"logger"`
NATS client.Config `json:"nats,omitempty" koanf:"nats"`
}
)

// New reads configuration with koanf.
func New() Config {
var instance Config

k := koanf.New(".")

// load default configuration from file
if err := k.Load(structs.Provider(Default(), "koanf"), nil); err != nil {
log.Fatalf("error loading default: %s", err)
}

// load configuration from file
if err := k.Load(file.Provider("config.yaml"), yaml.Parser()); err != nil {
log.Printf("error loading config.yaml")
}

// load environment variables
if err := k.Load(env.Provider(Prefix, ".", func(s string) string {
return strings.ReplaceAll(strings.ToLower(
strings.TrimPrefix(s, Prefix)), "__", ".")
}), nil); err != nil {
log.Printf("error loading environment variables: %s", err)
}

if err := k.Unmarshal("", &instance); err != nil {
log.Fatalf("error unmarshalling config: %s", err)
}

indent, err := json.MarshalIndent(instance, "", "\t")
if err != nil {
log.Fatalf("error marshalling config to json: %s", err)
}

indent = pretty.Color(indent, nil)
tmpl := `
================ Loaded Configuration ================
%s
======================================================
`
log.Printf(tmpl, string(indent))

return instance
}
Loading

0 comments on commit 25f8c9e

Please sign in to comment.