Skip to content

Commit ec4427a

Browse files
committed
support for tcp/udp routers
1 parent 2458c4f commit ec4427a

File tree

4 files changed

+66
-17
lines changed

4 files changed

+66
-17
lines changed

keymate/etcd.go

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type etcdKeyValue map[string]string
1616

1717
type EtcdKeymateManager struct {
1818
client *etcd.Client
19+
cfg *traefikkeymate.Config
1920
}
2021

2122
func NewEtcdManager(cfg *traefikkeymate.Config) (KeymateConnector, error) {
@@ -26,35 +27,58 @@ func NewEtcdManager(cfg *traefikkeymate.Config) (KeymateConnector, error) {
2627
return nil, fmt.Errorf("failed to connect to etcd: %v", err)
2728
}
2829

30+
// Validate that the default fields are set in the configuraiton
31+
if cfg.Traefik.DefaultEntrypoint == "" {
32+
return nil, fmt.Errorf("defautl entrypoint cannot be empty")
33+
}
34+
if cfg.Traefik.DefaultPrefix == "" {
35+
return nil, fmt.Errorf("default prefix cannot be empty")
36+
}
37+
2938
return &EtcdKeymateManager{
3039
client: client,
40+
cfg: cfg,
3141
}, nil
3242
}
3343

34-
func validateTarget(target *traefikkeymate.Target) error {
44+
func (m *EtcdKeymateManager) validateTarget(target *traefikkeymate.Target) error {
3545
// Name cannot be empty
3646
if target.Name == "" {
3747
return fmt.Errorf("target name cannot be empty")
3848
}
3949

4050
// Prefix cannot be empty
4151
if target.Prefix == "" {
42-
return fmt.Errorf("prefix for target named %s cannot be empty", target.Name)
52+
target.Prefix = m.cfg.Traefik.DefaultPrefix
53+
}
54+
55+
if target.Entrypoint == "" {
56+
target.Entrypoint = m.cfg.Traefik.DefaultEntrypoint
4357
}
4458

4559
// Rule cannot be empty
4660
if target.Rule == "" {
4761
return fmt.Errorf("prefix for target named %s cannot be empty", target.Name)
4862
}
4963

64+
if target.Type == "" {
65+
log.Warnf("target %s has an empty type, using http...", target.Name)
66+
target.Type = "http"
67+
}
68+
5069
return nil
5170
}
5271

5372
func (m *EtcdKeymateManager) deleteTarget(ctx context.Context, target *traefikkeymate.Target) []error {
73+
err := m.validateTarget(target)
74+
if err != nil {
75+
return []error{fmt.Errorf("invalid target: %v", err)}
76+
}
77+
5478
keyPrefixes := []string{
55-
fmt.Sprintf("%s/http/routers/%s", target.Prefix, target.Name),
56-
fmt.Sprintf("%s/http/services/%s", target.Prefix, target.Name),
57-
fmt.Sprintf("%s/http/middlewares/%s", target.Prefix, target.Name),
79+
fmt.Sprintf("%s/%s/routers/%s", target.Prefix, target.Type, target.Name),
80+
fmt.Sprintf("%s/%s/services/%s", target.Prefix, target.Type, target.Name),
81+
fmt.Sprintf("%s/%s/middlewares/%s", target.Prefix, target.Type, target.Name),
5882
}
5983

6084
var errs []error
@@ -73,40 +97,47 @@ func valuesForMiddlewares(target *traefikkeymate.Target, middlewares []*traefikk
7397
var middlewareNames []string
7498
for _, middleware := range middlewares {
7599
for key, value := range middleware.Values {
76-
keys[fmt.Sprintf("%s/http/middlewares/%s/%s/%s", target.Prefix, middleware.Name, middleware.Kind, key)] = value
100+
keys[fmt.Sprintf("%s/%s/middlewares/%s/%s/%s", target.Prefix, target.Type, middleware.Name, middleware.Kind, key)] = value
77101
}
78102

79103
middlewareNames = append(middlewareNames, middleware.Name)
80104
}
81105

82106
if len(middlewareNames) > 0 {
83-
keys[fmt.Sprintf("%s/http/routers/%s/middlewares", target.Prefix, target.Name)] = strings.Join(middlewareNames, ",")
107+
keys[fmt.Sprintf("%s/%s/routers/%s/middlewares", target.Prefix, target.Type, target.Name)] = strings.Join(middlewareNames, ",")
84108
}
85109

86110
return keys
87111
}
88112

89113
func (m *EtcdKeymateManager) writeTarget(ctx context.Context, target *traefikkeymate.Target) error {
90114
keys := etcdKeyValue{
91-
fmt.Sprintf("%s/http/routers/%s/entrypoints", target.Prefix, target.Name): target.Entrypoint,
92-
fmt.Sprintf("%s/http/routers/%s/rule", target.Prefix, target.Name): target.Rule,
93-
fmt.Sprintf("%s/http/routers/%s/service", target.Prefix, target.Name): target.Name,
115+
fmt.Sprintf("%s/%s/routers/%s/entrypoints", target.Prefix, target.Type, target.Name): target.Entrypoint,
116+
fmt.Sprintf("%s/%s/routers/%s/rule", target.Prefix, target.Type, target.Name): target.Rule,
117+
fmt.Sprintf("%s/%s/routers/%s/service", target.Prefix, target.Type, target.Name): target.Name,
94118
}
95119

96120
// Set loadbalancing between the endpoints
97121
for id, url := range target.ServerURLs {
98122
serverURL := url
99123

100-
// Check we have a scheme in the url to the server
101-
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
102-
log.Warnf("server URL for target %s doesn't have a scheme, adding http", target.Name)
103-
serverURL = fmt.Sprintf("http://%s", url)
124+
// Check we have a scheme in the url to the server with http routers
125+
if target.Type == "http" {
126+
if !strings.Contains(url, "//") {
127+
log.Warnf("server URL for target %s doesn't have a scheme, adding %s", target.Type, target.Name)
128+
serverURL = fmt.Sprintf("%s://%s", target.Type, url)
129+
}
130+
}
131+
132+
suffix := "url"
133+
if target.Type != "http" {
134+
suffix = "address"
104135
}
105136

106-
keys[fmt.Sprintf("%s/http/services/%s/loadbalancer/servers/%d/url", target.Prefix, target.Name, id)] = serverURL
137+
keys[fmt.Sprintf("%s/%s/services/%s/loadbalancer/servers/%d/%s", target.Prefix, target.Type, target.Name, id, suffix)] = serverURL
107138
}
108139

109-
if target.TLS {
140+
if target.TLS && target.Type == "http" {
110141
keys[fmt.Sprintf("%s/http/routers/%s/tls", target.Prefix, target.Name)] = "true"
111142
}
112143

@@ -145,7 +176,7 @@ func (m *EtcdKeymateManager) ApplyConfig(ctx context.Context, cfg *traefikkeymat
145176
target.Entrypoint = cfg.Traefik.DefaultEntrypoint
146177
}
147178

148-
if err := validateTarget(target); err != nil {
179+
if err := m.validateTarget(target); err != nil {
149180
errs = append(errs, err)
150181
continue
151182
}

nix/configuration-test.nix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ let
66
address: ":80"
77
traefik:
88
address: ":8080"
9+
ssh:
10+
address: ":2222"
911
1012
providers:
1113
etcd:
@@ -65,6 +67,12 @@ in {
6567
defaultEntrypoint = "web";
6668
defaultPrefix = "traefik";
6769
targets = {
70+
"ssh" = {
71+
serverUrls = [ "127.0.0.1:22" ];
72+
routerType = "tcp";
73+
rule = "HostSNI(`*`)";
74+
entrypoint = "ssh";
75+
};
6876
"path" = {
6977
rule = "Path(`/path/`)";
7078
serverUrls = [ "127.0.0.1:8181" ];

nix/modules/default.nix

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ let
1313
targets = (attrValues (mapAttrs (name: target: {
1414
inherit (target) entrypoint prefix rule tls;
1515
name = name;
16+
type = target.routerType;
1617
urls = target.serverUrls;
1718
middlewares = (attrValues (mapAttrs (name: middleware: {
1819
name = name;
@@ -51,6 +52,14 @@ let
5152
'';
5253
};
5354

55+
routerType = mkOption {
56+
type = types.enum [ "http" "tcp" "udp" ];
57+
default = "http";
58+
description = mkDoc ''
59+
Type of traefik router for this target
60+
'';
61+
};
62+
5463
entrypoint = mkOption {
5564
type = types.str;
5665
default = "web";

target.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package traefikkeymate
22

33
type Target struct {
44
Name string `json:"name"`
5+
Type string `json:"type"`
56
ServerURLs []string `json:"urls"`
67
Entrypoint string `json:"entrypoint"`
78
Middlewares []*Middleware `json:"middlewares"`

0 commit comments

Comments
 (0)