1package app
2
3import (
4 "context"
5 "fmt"
6
7 trafficadapter "github.com/bnema/gordon/internal/adapters/in/traffic"
8 "github.com/bnema/gordon/internal/boundaries/in"
9 "github.com/bnema/gordon/internal/domain"
10 servicecfg "github.com/bnema/gordon/internal/usecase/services"
11 trafficbuilder "github.com/bnema/gordon/internal/usecase/traffic"
12)
13
14func applyTrafficRuntimeConfig(ctx context.Context, manager *trafficadapter.Manager, cfg Config, configSvc in.ConfigService) error {
15 if manager == nil || configSvc == nil {
16 return nil
17 }
18 standaloneServices, err := servicecfg.ToDomain(cfg.Services)
19 if err != nil {
20 return fmt.Errorf("convert standalone service config: %w", err)
21 }
22 graph, err := trafficbuilder.Build(trafficbuilder.Input{
23 EntryPoints: cfg.EntryPoints,
24 Traffic: cfg.Traffic,
25 Routes: configSvc.GetRoutes(ctx),
26 ExternalRoutes: configSvc.GetExternalRoutes(),
27 NetworkServices: cfg.NetworkServices,
28 Services: standaloneServices,
29 })
30 if err != nil {
31 return fmt.Errorf("build traffic graph: %w", err)
32 }
33 owned, err := trafficRuntimeGraph(graph)
34 if err != nil {
35 return fmt.Errorf("filter traffic graph for runtime ownership: %w", err)
36 }
37 if err := manager.Apply(ctx, &owned); err != nil {
38 return fmt.Errorf("apply traffic graph: %w", err)
39 }
40 return nil
41}
42
43func trafficRuntimeGraph(graph domain.TrafficGraph) (domain.TrafficGraph, error) {
44 ownedEntryPoints := map[string]struct{}{}
45 filtered := domain.TrafficGraph{Options: graph.Options}
46 for _, entryPoint := range graph.EntryPoints {
47 if trafficManagerOwnsEntryPoint(entryPoint) {
48 filtered.EntryPoints = append(filtered.EntryPoints, entryPoint)
49 ownedEntryPoints[entryPoint.Name] = struct{}{}
50 }
51 }
52
53 usedServices := map[string]struct{}{}
54 for _, router := range graph.Routers {
55 if _, ok := ownedEntryPoints[router.EntryPoint]; !ok {
56 if trafficManagerRouterProtocol(router.Protocol) {
57 return domain.TrafficGraph{}, fmt.Errorf("traffic router %q targets entrypoint %q, which is not owned by the traffic manager", router.Name, router.EntryPoint)
58 }
59 continue
60 }
61 filtered.Routers = append(filtered.Routers, router)
62 usedServices[router.Service] = struct{}{}
63 }
64 for _, service := range graph.Services {
65 if _, ok := usedServices[service.Name]; ok {
66 filtered.Services = append(filtered.Services, service)
67 }
68 }
69 return filtered, nil
70}
71
72func trafficManagerRouterProtocol(protocol domain.RouterProtocol) bool {
73 switch protocol {
74 case domain.RouterProtocolTCP, domain.RouterProtocolUDP, domain.RouterProtocolTLSPassthrough:
75 return true
76 default:
77 return false
78 }
79}
80
81func trafficManagerOwnsEntryPoint(entryPoint domain.EntryPoint) bool {
82 switch entryPoint.Protocol {
83 case domain.EntryPointProtocolTLSMux, domain.EntryPointProtocolSmartTCP, domain.EntryPointProtocolTCP, domain.EntryPointProtocolUDP:
84 return true
85 default:
86 return false
87 }
88}