mirror of
https://github.com/KevinMidboe/traefik-etcd-advertiser.git
synced 2025-10-29 09:50:20 +00:00
init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
vendor/
|
||||||
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.PHONY: build install server
|
||||||
|
|
||||||
|
PROJECT_NAME=$(shell basename $(CURDIR))
|
||||||
|
|
||||||
|
## build: build the application
|
||||||
|
build:
|
||||||
|
export GO111MODULE="auto"; \
|
||||||
|
go mod download; \
|
||||||
|
go mod vendor; \
|
||||||
|
CGO_ENABLED=0 go build -a -ldflags '-s' -installsuffix cgo -o main main.go
|
||||||
|
|
||||||
|
## install: fetches go modules
|
||||||
|
install:
|
||||||
|
export GO111MODULE="on"; \
|
||||||
|
go mod tidy; \
|
||||||
|
go mod download \
|
||||||
|
|
||||||
|
## server: runs the server with -race
|
||||||
|
server:
|
||||||
|
export GO111MODULE="on"; \
|
||||||
|
go run main.go
|
||||||
|
|
||||||
|
## modd: Monitors the directory, and recompiles your app every time a file changes. Also runs tests.
|
||||||
|
## (To install modd, run: go get github.com/cortesi/modd/cmd/modd)
|
||||||
|
modd:
|
||||||
|
modd
|
||||||
24
assets/docker-compose-2.yml
Normal file
24
assets/docker-compose-2.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: webapp
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.webapp.rule=Host(`webapp.localhost`)"
|
||||||
|
- "traefik.http.routers.webapp.entrypoints=web"
|
||||||
|
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.webapp.middlewares=redirect-to-https"
|
||||||
|
- "traefik.http.routers.webapp.tls=true"
|
||||||
|
- "traefik.http.services.webapp.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: my-backend-app:latest
|
||||||
|
container_name: backend
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.backend.rule=Host(`backend.localhost`)"
|
||||||
|
- "traefik.http.routers.backend.entrypoints=web"
|
||||||
|
- "traefik.http.routers.backend.tls=true"
|
||||||
|
- "traefik.http.services.backend.loadbalancer.server.port=5000" # Port exposed by the backend app
|
||||||
24
assets/docker-compose.yml
Normal file
24
assets/docker-compose.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: webapp
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.webapp.rule=Host(`webapp.localhost`)"
|
||||||
|
- "traefik.http.routers.webapp.entrypoints=web"
|
||||||
|
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.webapp.middlewares=redirect-to-https"
|
||||||
|
- "traefik.http.routers.webapp.tls=true"
|
||||||
|
- "traefik.http.services.webapp.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: my-backend-app:latest
|
||||||
|
container_name: backend
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.backend.rule=Host(`backend.localhost`)"
|
||||||
|
- "traefik.http.routers.backend.entrypoints=web"
|
||||||
|
- "traefik.http.routers.backend.tls=true"
|
||||||
|
- "traefik.http.services.backend.loadbalancer.server.port=5000" # Port exposed by the backend app
|
||||||
34
assets/dynamic.yml
Normal file
34
assets/dynamic.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
http:
|
||||||
|
routers:
|
||||||
|
request-router:
|
||||||
|
rule: "Host(`request.test`)"
|
||||||
|
service: request-service
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
services:
|
||||||
|
request-service:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://seasoned.schleppe:5000"
|
||||||
|
weight: 100
|
||||||
|
passHostHeader: true
|
||||||
|
mirrored-service:
|
||||||
|
mirroring:
|
||||||
|
service: example-service
|
||||||
|
mirrorBody: true
|
||||||
|
maxBodySize: 1024
|
||||||
|
mirrors:
|
||||||
|
- name: mirror1
|
||||||
|
percent: 10
|
||||||
|
url: http://example.com
|
||||||
|
- name: mirror2
|
||||||
|
percent: 20
|
||||||
|
url: http://example.org
|
||||||
|
healthCheck:
|
||||||
|
service: "request-service"
|
||||||
|
|
||||||
|
middlewares:
|
||||||
|
redirect-to-https:
|
||||||
|
redirectScheme:
|
||||||
|
permanent: false
|
||||||
|
scheme: https
|
||||||
129
client/etcd/etcd.go
Normal file
129
client/etcd/etcd.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
etcd "go.etcd.io/etcd/client/v3"
|
||||||
|
"google.golang.org/grpc/connectivity"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EtcdManager struct {
|
||||||
|
client *etcd.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type EtcdPacket struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient() (*EtcdManager, error) {
|
||||||
|
fmt.Println("setting up etcd client")
|
||||||
|
|
||||||
|
endpoints := []string{"localhost:2379"}
|
||||||
|
if value, exists := os.LookupEnv("ETCD_ENDPOINTS"); exists {
|
||||||
|
endpoints = strings.Split(value, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := etcd.New(etcd.Config{
|
||||||
|
Endpoints: endpoints,
|
||||||
|
DialTimeout: 30 * time.Second,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create etcd manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr := &EtcdManager{client}
|
||||||
|
|
||||||
|
err = mgr.runWithTimeout(func(e *EtcdManager, ctx context.Context) error {
|
||||||
|
etcdStatus, err := e.client.Status(ctx, e.client.Endpoints()[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get etcd status: %v", err)
|
||||||
|
}
|
||||||
|
if len(etcdStatus.Errors) > 0 {
|
||||||
|
return fmt.Errorf("etcd server has errors: %v", etcdStatus.Errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
connState := e.client.ActiveConnection().GetState()
|
||||||
|
if connState != connectivity.Ready && connState != connectivity.Idle {
|
||||||
|
return fmt.Errorf("etcd connection is in unexpecetd state: %s",
|
||||||
|
e.client.ActiveConnection().GetState())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mgr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EtcdManager) runWithTimeout(runnable func(e *EtcdManager, ctx context.Context) error) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return runnable(e, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runWithTimeoutReturning[R any](
|
||||||
|
e *EtcdManager,
|
||||||
|
runnable func(e *EtcdManager, ctx context.Context) (R, error),
|
||||||
|
) (R, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return runnable(e, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EtcdManager) Put(key string, val string, opts ...etcd.OpOption) error {
|
||||||
|
log.Println("etcd: Putting key", key, val)
|
||||||
|
return e.runWithTimeout(func(e *EtcdManager, ctx context.Context) error {
|
||||||
|
_, err := e.client.Put(ctx, key, val, opts...)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EtcdManager) Get(key string, opts ...etcd.OpOption) (string, error) {
|
||||||
|
log.Println("etcd: Getting key", key)
|
||||||
|
return runWithTimeoutReturning(e, func(e *EtcdManager, ctx context.Context) (string, error) {
|
||||||
|
resp, err := e.client.Get(ctx, key, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return string(resp.Kvs[0].Value), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EtcdManager) Remove(key string) error {
|
||||||
|
log.Println("etcd: Removing key", key)
|
||||||
|
return e.runWithTimeout(func(e *EtcdManager, ctx context.Context) error {
|
||||||
|
_, err := e.client.Delete(ctx, key)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveDuplicatePackets(packets *[]EtcdPacket) {
|
||||||
|
keys := make(map[string]bool)
|
||||||
|
list := []EtcdPacket{}
|
||||||
|
keysRm := []string{}
|
||||||
|
|
||||||
|
for _, entry := range *packets {
|
||||||
|
if _, ok := keys[entry.Key]; !ok {
|
||||||
|
keys[entry.Key] = true
|
||||||
|
list = append(list, entry)
|
||||||
|
} else {
|
||||||
|
keysRm = append(keysRm, entry.Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(keysRm) > 0 {
|
||||||
|
slog.Warn(fmt.Sprintf("keys squashed: %s", keysRm))
|
||||||
|
}
|
||||||
|
|
||||||
|
*packets = list
|
||||||
|
}
|
||||||
26
config/config.go
Normal file
26
config/config.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/kelseyhightower/envconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config contains environment variables.
|
||||||
|
type Config struct {
|
||||||
|
EtcdEndpoint string `envconfig:"ETCD_ENDPOINTS"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConfig reads environment variables, populates and returns Config.
|
||||||
|
func LoadConfig() (*Config, error) {
|
||||||
|
if err := godotenv.Load(); err != nil {
|
||||||
|
log.Println("No .env file found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var c Config
|
||||||
|
|
||||||
|
err := envconfig.Process("", &c)
|
||||||
|
|
||||||
|
return &c, err
|
||||||
|
}
|
||||||
18
converter/json.go
Normal file
18
converter/json.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package converter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TraefikToJSON(config *dynamic.Configuration) map[string]interface{} {
|
||||||
|
var data map[string]interface{}
|
||||||
|
jsonData, _ := json.Marshal(config)
|
||||||
|
if err := json.Unmarshal(jsonData, &data); err != nil {
|
||||||
|
log.Printf("failed to unmarshal JSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
28
converter/yaml.go
Normal file
28
converter/yaml.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package converter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TraefikFromYaml(filePath string) (*dynamic.Configuration, error) {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var cfg dynamic.Configuration
|
||||||
|
decoder := yaml.NewDecoder(file)
|
||||||
|
if err := decoder.Decode(&cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TraefikToYaml(config *dynamic.Configuration) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
65
generator/docker.go
Normal file
65
generator/docker.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package generator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/compose-spec/compose-go/v2/cli"
|
||||||
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/client/etcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dockerLabelToEtcdKey(key string) string {
|
||||||
|
return strings.ReplaceAll(key, ".", "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseDockerCompose(composeFilePath string) (*types.Project, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
options, err := cli.NewProjectOptions(
|
||||||
|
[]string{composeFilePath},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
project, err := options.LoadProject(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return project, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPacket2(config *types.Project) []etcd.EtcdPacket {
|
||||||
|
blocks := []etcd.EtcdPacket{}
|
||||||
|
|
||||||
|
fmt.Println("DockerToEtcd")
|
||||||
|
if config.Services == nil || len(config.Services) < 1 {
|
||||||
|
fmt.Println("services not found - skipping")
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
for serviceName, _ := range config.Services {
|
||||||
|
if config.Services[serviceName].Labels == nil {
|
||||||
|
fmt.Println("sevice, but no labels found - continuing")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, val := range config.Services[serviceName].Labels {
|
||||||
|
blocks = append(blocks, etcd.EtcdPacket{
|
||||||
|
Key: dockerLabelToEtcdKey(key),
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func DockerToEtcd(config *types.Project, packetList *[]etcd.EtcdPacket) {
|
||||||
|
items := createPacket2(config)
|
||||||
|
|
||||||
|
*packetList = append(*packetList, items...)
|
||||||
|
}
|
||||||
83
generator/traefik.go
Normal file
83
generator/traefik.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package generator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/client/etcd"
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/converter"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const traefikPrefix = "traefik"
|
||||||
|
|
||||||
|
func isKnownGenericType(value interface{}) bool {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
return true
|
||||||
|
case float64:
|
||||||
|
return true
|
||||||
|
case bool:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
slog.Debug(fmt.Sprintf("found unknown generic %s\n", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertToGeneric(value interface{}) string {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case float64:
|
||||||
|
return fmt.Sprintf("%d", int(math.Floor(v)))
|
||||||
|
case bool:
|
||||||
|
return strconv.FormatBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown type"
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively walks the JSON object and creates internal
|
||||||
|
// `etcdPackets` per leaf node, returns list of packets.
|
||||||
|
func createPacket(item interface{}, parentKey string) []etcd.EtcdPacket {
|
||||||
|
blocks := []etcd.EtcdPacket{}
|
||||||
|
|
||||||
|
switch itemD := item.(type) {
|
||||||
|
// input is JSON object
|
||||||
|
case map[string]interface{}:
|
||||||
|
for key, value := range itemD {
|
||||||
|
// check for generic value type vs nested object,
|
||||||
|
// either create block or recursively call obj again
|
||||||
|
|
||||||
|
if isKnownGenericType(value) {
|
||||||
|
blocks = append(blocks, etcd.EtcdPacket{
|
||||||
|
Key: parentKey + "/" + key,
|
||||||
|
Value: convertToGeneric(value),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
blocks = append(blocks, createPacket(itemD[key], fmt.Sprintf("%s/%s", parentKey, key))...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// input is JSON list
|
||||||
|
case []interface{}:
|
||||||
|
for i, item := range itemD {
|
||||||
|
blocks = append(blocks, createPacket(item, parentKey+"/"+strconv.Itoa(i))...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func TraefikToEtcd(config *dynamic.Configuration, packetList *[]etcd.EtcdPacket) {
|
||||||
|
// always convert to json before converting to etcd
|
||||||
|
data := converter.TraefikToJSON(config)
|
||||||
|
|
||||||
|
// generate list of etcd commands
|
||||||
|
items := createPacket(data, traefikPrefix)
|
||||||
|
*packetList = append(*packetList, items...)
|
||||||
|
}
|
||||||
|
|
||||||
97
go.mod
Normal file
97
go.mod
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
module github.com/kevinmidboe/traefik-etcd-advertiser
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/compose-spec/compose-go/v2 v2.4.7
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/traefik/traefik/v3 v3.3.2
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.17
|
||||||
|
google.golang.org/grpc v1.67.1
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
k8s.io/api v0.32.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aws/aws-sdk-go v1.44.327 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
|
github.com/go-acme/lego/v4 v4.21.0 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||||
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
github.com/google/go-github/v28 v28.1.1 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
|
||||||
|
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||||
|
github.com/http-wasm/http-wasm-host-go v0.7.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||||
|
github.com/miekg/dns v1.1.62 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/traefik/paerser v0.2.1 // indirect
|
||||||
|
github.com/unrolled/render v1.0.2 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.17 // indirect
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/log v0.8.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.8.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.26.0 // indirect
|
||||||
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||||
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
|
golang.org/x/net v0.33.0 // indirect
|
||||||
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
|
golang.org/x/text v0.21.0 // indirect
|
||||||
|
golang.org/x/tools v0.28.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||||
|
google.golang.org/protobuf v1.35.2 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
k8s.io/apimachinery v0.32.0 // indirect
|
||||||
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
|
)
|
||||||
66
main.go
Normal file
66
main.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/client/etcd"
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/config"
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/converter"
|
||||||
|
"github.com/kevinmidboe/traefik-etcd-advertiser/generator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getArgvFilename() string {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
log.Fatalf("Usage: %s <path-to-yaml-file>\n", os.Args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := os.Args[1]
|
||||||
|
return filename
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_, err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error from config loader", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup etcd client
|
||||||
|
// etcdManager, err := etcd.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var packets []etcd.EtcdPacket
|
||||||
|
|
||||||
|
// parse traefik config from file
|
||||||
|
filename := getArgvFilename()
|
||||||
|
if strings.Contains(filename, "docker-compose.yml") {
|
||||||
|
// build etcd packets from docker-compose config
|
||||||
|
dockerConfig, err := generator.ParseDockerCompose(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generator.PrintLabels(labels)
|
||||||
|
fmt.Println("compose")
|
||||||
|
log.Println(dockerConfig)
|
||||||
|
// generator.TraefikToEtcd(traefikConfig, &packets)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// build etcd packets from traefik config
|
||||||
|
traefikConfig, err := converter.TraefikFromYaml(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error loading traefik YAML config file: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.TraefikToEtcd(traefikConfig, &packets)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, packet := range packets {
|
||||||
|
log.Println(packet)
|
||||||
|
// etcdManager.Put(packet.Key, packet.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user