Compare commits

..

No commits in common. "main" and "v1" have entirely different histories.
main ... v1

11 changed files with 45 additions and 135 deletions

View file

@ -2,13 +2,14 @@
name: Build and release name: Build and release
on: on:
workflow_dispatch: release:
inputs: types: [published]
version: # workflow_dispatch:
type: string # inputs:
description: 'Version' # version:
required: true # description: 'Version'
default: 'v0' # required: true
# default: 'v0'
jobs: jobs:
test: test:
@ -23,19 +24,24 @@ jobs:
with: with:
go-version: '1.23' go-version: '1.23'
# - name: Install dependencies
# run: |
# sudo apt-get update
# sudo apt-get install -y task
- name: Run tests - name: Run tests
run: task test run: task test
- name: Build - name: Build
run: | run: |
task build VERSION=${{ github.event.inputs.version }} task build VERSION=${{ github.ref_name }}
- uses: actions/forgejo-release@v2 - name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
token: ${{ secrets.GITHUB_TOKEN }} upload_url: ${{ github.event.release.upload_url }}
direction: upload asset_path: ./lobby2-${{ github.ref_name }}-amd64
tag: ${{ github.event.inputs.version }} asset_name: lobby2-${{ github.ref_name }}-amd64
title: ${{ github.event.inputs.version }} asset_content_type: application/octet-stream
url: https://gitea.ceperka.net
release-dir: bin/
release-notes-assistant: true

2
.gitignore vendored
View file

@ -1,5 +1,3 @@
tmp/ tmp/
__debug* __debug*
main main
bin/
nodes.json

2
.vscode/launch.json vendored
View file

@ -29,7 +29,7 @@
"env": { "env": {
"DUMP_PATH": "../tmp/nodes.json", "DUMP_PATH": "../tmp/nodes.json",
"CONFIG_PATH": "../tmp/config.json", "CONFIG_PATH": "../tmp/config.json",
"NODE_PATH": "../tmp/node.json" "NODE_DIR_PATH": "../tmp/node"
}, },
"args": [ "args": [
"node" "node"

View file

@ -18,10 +18,4 @@ tasks:
build: build:
cmds: cmds:
- go mod tidy - go mod tidy
- mkdir -p bin - go build -o lobby2-{{ .VERSION }}-amd64 cli/*.go
- env CGO_ENABLED=0 go build -o bin/lobby2-{{ .VERSION }}-linux-amd64 cli/*.go
deploy:
cmds:
- task: build
- scp bin/lobby2-{{ .VERSION }}-linux-amd64 rosti-db:/usr/local/bin/lobby2.tmp
- ssh rosti-db mv /usr/local/bin/lobby2.tmp /usr/local/bin/lobby2

View file

@ -53,7 +53,6 @@ func (a *API) Run() error {
a.e.GET("/nodes", a.listHandler) a.e.GET("/nodes", a.listHandler)
a.e.GET("/nodes/:hostname", a.getHandler) a.e.GET("/nodes/:hostname", a.getHandler)
a.e.POST("/nodes/:hostname", a.refreshHandler) a.e.POST("/nodes/:hostname", a.refreshHandler)
a.e.GET("/prometheus/:service", a.prometheusHandler)
// Start the server in a goroutine so that it doesn't block the signal listening // Start the server in a goroutine so that it doesn't block the signal listening
return a.e.Start(a.listen) return a.e.Start(a.listen)
@ -112,18 +111,3 @@ func (a *API) refreshHandler(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)
} }
// @Summary Prometheus service discovery
// @Description Return one nodes based on given hostname
// @Produce application/json
// @Success 200 {array} []prometheusDiscovery "Node details"
// @Failure 401 {object} Message "Forbidden access"
// @Security Bearer
// @Router /prometheus/{service} [get]
func (a *API) prometheusHandler(c echo.Context) error {
ss := c.Param("service")
pds := nodes.GetPrometheusSD(a.np, ss)
return c.JSONPretty(http.StatusOK, pds, " ")
}

View file

@ -28,7 +28,7 @@ func masterAction(c *cli.Context) error {
func nodeAction(c *cli.Context) error { func nodeAction(c *cli.Context) error {
cfg := GetConfig() cfg := GetConfig()
r := refresher.NewRefresher(cfg.NodePath, cfg.ConfigPath) r := refresher.NewRefresher(cfg.NodeDirPath, cfg.ConfigPath)
r.Loop() r.Loop()
return nil return nil
@ -52,23 +52,3 @@ func printAction(c *cli.Context) error {
return nil return nil
} }
func prometheusAction(c *cli.Context) error {
cfg := GetConfig()
np := nodes.NewNodesProcessor(cfg.DumpPath, cfg.DropAfterSeconds)
pds := nodes.GetPrometheusSD(np, "node")
for _, pd := range pds {
body, err := json.MarshalIndent(pd, "", " ")
if err != nil {
fmt.Printf("failed to marshal prometheus discovery: %v\n", err)
os.Exit(1)
}
fmt.Println(string(body))
}
return nil
}

View file

@ -10,9 +10,9 @@ type Config struct {
APIListen string `envconfig:"LISTEN" default:"0.0.0.0:1352"` APIListen string `envconfig:"LISTEN" default:"0.0.0.0:1352"`
APIToken string `envconfig:"TOKEN" default:""` APIToken string `envconfig:"TOKEN" default:""`
DumpPath string `envconfig:"DUMP_PATH" default:"/var/lib/lobby2/nodes.json"` DumpPath string `envconfig:"DUMP_PATH" default:"/var/lib/lobby2/nodes.json"`
ConfigPath string `envconfig:"CONFIG_PATH" default:"/etc/lobby2/config.json"` ConfigPath string `envconfig:"CONFIG_PATH" default:"/var/lib/lobby2/config.json"`
NodePath string `envconfig:"NODE_PATH" default:"/etc/lobby2/node.json"` NodeDirPath string `envconfig:"NODE_DIR_PATH" default:"/var/lib/lobby2/node"`
DropAfterSeconds int64 `envconfig:"DROP_AFTER_SECONDS" default:"60"` DropAfterSeconds int64 `envconfig:"DROP_AFTER_SECONDS" default:"60"`
} }

View file

@ -27,11 +27,6 @@ func main() {
Usage: "Prints all discovered nodes", Usage: "Prints all discovered nodes",
Action: printAction, Action: printAction,
}, },
{
Name: "prometheus",
Usage: "Prints Prometheus Service Discovery",
Action: prometheusAction,
},
}, },
} }

View file

@ -32,12 +32,11 @@ func TestNodesProcessor_Refresh(t *testing.T) {
np.Refresh("test", Labels{"mylabel"}, KV{"mykey": "my value"}) np.Refresh("test", Labels{"mylabel"}, KV{"mykey": "my value"})
np.Refresh("test2", Labels{"mylabel3"}, KV{"mykey3": "my value3"}) np.Refresh("test2", Labels{"mylabel3"}, KV{"mykey3": "my value3"})
nodeTest, _ := np.Get("test") nodes := np.List()
nodeTest2, _ := np.Get("test2") assert.Equal(t, "test", nodes[0].HostName)
assert.Equal(t, "test", nodeTest.HostName) assert.Contains(t, nodes[0].Labels, "mylabel")
assert.Contains(t, nodeTest.Labels, "mylabel") assert.Equal(t, "test2", nodes[1].HostName)
assert.Equal(t, "test2", nodeTest2.HostName) assert.Contains(t, nodes[1].Labels, "mylabel3")
assert.Contains(t, nodeTest2.Labels, "mylabel3")
} }
func TestNodesProcessor_DumpLoad(t *testing.T) { func TestNodesProcessor_DumpLoad(t *testing.T) {

View file

@ -1,45 +0,0 @@
package nodes
import (
"fmt"
"strings"
)
type prometheusDiscovery struct {
Labels map[string]string `json:"Labels"`
Targets []string `json:"Targets"`
}
func GetPrometheusSD(p *NodesProcessor, ss string) []prometheusDiscovery {
ns := p.List()
pds := []prometheusDiscovery{
{
Labels: make(map[string]string),
Targets: []string{},
},
}
for _, node := range ns {
port, ok := node.KV["prometheus_port"]
if !ok {
port = "9999"
}
host, ok := node.KV["prometheus_host"]
if !ok {
host = node.HostName
}
v, ok := node.KV["prometheus_exporters"]
if ok {
services := strings.Split(v, ",")
for _, service := range services {
if ss == service {
pds[0].Targets = append(pds[0].Targets, fmt.Sprintf("%s:%s", host, port))
}
}
}
}
return pds
}

View file

@ -7,24 +7,25 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path"
"time" "time"
"gitea.ceperka.net/rosti/lobby2/nodes" "gitea.ceperka.net/rosti/lobby2/nodes"
) )
const refreshIntervalSeconds = 15 const refreshIntervalSeconds = 15
const nodeFileName = "node.json"
// Refresher loads local node info and sends them to the master node. // Refresher loads local node info and sends them to the master node.
type Refresher struct { type Refresher struct {
configPath string configPath string
nodePath string nodeDirPath string
} }
func NewRefresher(nodePath string, configPath string) *Refresher { func NewRefresher(nodeDirPath string, configPath string) *Refresher {
return &Refresher{ return &Refresher{
nodePath: nodePath, nodeDirPath: nodeDirPath,
configPath: configPath, configPath: configPath,
} }
} }
@ -112,7 +113,7 @@ func (r *Refresher) getConfig() (NodeConfig, error) {
// TODO: rewrite this to load Node structure // TODO: rewrite this to load Node structure
func (r *Refresher) loadNode() (*nodes.Node, error) { func (r *Refresher) loadNode() (*nodes.Node, error) {
filePath := r.nodePath filePath := path.Join(r.nodeDirPath, nodeFileName)
_, err := os.Stat(filePath) _, err := os.Stat(filePath)
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = r.initNodeFile() err = r.initNodeFile()
@ -121,7 +122,7 @@ func (r *Refresher) loadNode() (*nodes.Node, error) {
} }
} }
content, err := os.ReadFile(r.nodePath) content, err := os.ReadFile(path.Join(r.nodeDirPath, nodeFileName))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err) return nil, fmt.Errorf("failed to read file: %w", err)
} }
@ -155,7 +156,7 @@ func (r *Refresher) initNodeFile() error {
return fmt.Errorf("failed to marshal node: %w", err) return fmt.Errorf("failed to marshal node: %w", err)
} }
err = os.WriteFile(r.nodePath, nodeBytes, 0640) err = os.WriteFile(path.Join(r.nodeDirPath, nodeFileName), nodeBytes, 0640)
if err != nil { if err != nil {
return fmt.Errorf("failed to write node file: %w", err) return fmt.Errorf("failed to write node file: %w", err)
} }
@ -164,11 +165,9 @@ func (r *Refresher) initNodeFile() error {
} }
func (r *Refresher) createNodePath() error { func (r *Refresher) createNodePath() error {
d := filepath.Dir(r.nodePath) _, err := os.Stat(r.nodeDirPath)
_, err := os.Stat(d)
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = os.MkdirAll(d, 0755) err = os.MkdirAll(r.nodeDirPath, 0755)
if err != nil { if err != nil {
return fmt.Errorf("failed to create node dir: %w", err) return fmt.Errorf("failed to create node dir: %w", err)
} }