Skip to content

Commit 1fe2307

Browse files
committed
feat: feats for onedr0p
1 parent 2cfde74 commit 1fe2307

File tree

8 files changed

+227
-60
lines changed

8 files changed

+227
-60
lines changed

internal/config/config.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type Config struct {
1010
Namespace string
1111
GatewayName string
1212
IngressClass string
13+
AutoGroup bool
1314
Output string
1415
DefaultInterval time.Duration
1516
DefaultDNSResolver string
@@ -21,8 +22,9 @@ func Load() *Config {
2122
cfg := &Config{}
2223
flag.StringVar(&cfg.Mode, "mode", "httproute", "Mode to run in: 'httproute' or 'ingress'")
2324
flag.StringVar(&cfg.Namespace, "namespace", "", "Namespace to watch (empty for all)")
24-
flag.StringVar(&cfg.GatewayName, "gateway", "", "Gateway name to filter HTTPRoutes (required for HTTPRoute mode)")
25-
flag.StringVar(&cfg.IngressClass, "ingress-class", "", "Ingress class to filter Ingresses (optional for Ingress mode)")
25+
flag.StringVar(&cfg.GatewayName, "gateway-name", "", "Gateway name to filter HTTPRoutes (optional)")
26+
flag.StringVar(&cfg.IngressClass, "ingress-class", "", "Ingress class to filter Ingresses (optional)")
27+
flag.BoolVar(&cfg.AutoGroup, "auto-group", false, "Automatically group endpoints by gateway name or ingress class")
2628
flag.StringVar(&cfg.Output, "output", "/config/gatus-sidecar.yaml", "File to write generated YAML")
2729
flag.DurationVar(&cfg.DefaultInterval, "default-interval", time.Minute, "Default interval value for endpoints")
2830
flag.StringVar(&cfg.DefaultDNSResolver, "default-dns", "tcp://1.1.1.1:53", "Default DNS resolver for endpoints")

internal/controller/controller.go

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ import (
88

99
"gopkg.in/yaml.v3"
1010

11-
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
12-
13-
networkingv1 "k8s.io/api/networking/v1"
1411
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1512
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
16-
"k8s.io/apimachinery/pkg/runtime"
1713
"k8s.io/apimachinery/pkg/runtime/schema"
1814
"k8s.io/apimachinery/pkg/watch"
1915
"k8s.io/client-go/dynamic"
@@ -22,51 +18,15 @@ import (
2218
"github.com/home-operations/gatus-sidecar/internal/config"
2319
"github.com/home-operations/gatus-sidecar/internal/endpoint"
2420
"github.com/home-operations/gatus-sidecar/internal/handler"
25-
"github.com/home-operations/gatus-sidecar/internal/state"
21+
"github.com/home-operations/gatus-sidecar/internal/manager"
2622
)
2723

2824
// Controller is a generic Kubernetes resource controller
2925
type Controller struct {
3026
gvr schema.GroupVersionResource
3127
handler handler.ResourceHandler
3228
convert func(*unstructured.Unstructured) (metav1.Object, error)
33-
stateManager *state.Manager
34-
}
35-
36-
// NewIngressController creates a controller for Ingress resources
37-
func NewIngressController(resourceHandler handler.ResourceHandler, stateManager *state.Manager) *Controller {
38-
return &Controller{
39-
gvr: schema.GroupVersionResource{
40-
Group: "networking.k8s.io",
41-
Version: "v1",
42-
Resource: "ingresses",
43-
},
44-
handler: resourceHandler,
45-
stateManager: stateManager,
46-
convert: func(u *unstructured.Unstructured) (metav1.Object, error) {
47-
ingress := &networkingv1.Ingress{}
48-
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, ingress); err != nil {
49-
return nil, fmt.Errorf("failed to convert to Ingress: %w", err)
50-
}
51-
return ingress, nil
52-
},
53-
}
54-
}
55-
56-
// NewHTTPRouteController creates a controller for HTTPRoute resources
57-
func NewHTTPRouteController(resourceHandler handler.ResourceHandler, stateManager *state.Manager) *Controller {
58-
return &Controller{
59-
gvr: gatewayv1.SchemeGroupVersion.WithResource("httproutes"),
60-
handler: resourceHandler,
61-
stateManager: stateManager,
62-
convert: func(u *unstructured.Unstructured) (metav1.Object, error) {
63-
route := &gatewayv1.HTTPRoute{}
64-
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, route); err != nil {
65-
return nil, fmt.Errorf("failed to convert to HTTPRoute: %w", err)
66-
}
67-
return route, nil
68-
},
69-
}
29+
stateManager *manager.Manager
7030
}
7131

7232
// Run starts the controller watch loop
@@ -180,6 +140,9 @@ func (c *Controller) handleEvent(cfg *config.Config, obj metav1.Object, eventTyp
180140
Conditions: []string{condition},
181141
}
182142

143+
// Apply resource-specific template if available
144+
c.handler.ApplyTemplate(cfg, obj, endpoint)
145+
183146
// Apply template overrides if present
184147
if templateData != nil {
185148
endpoint.ApplyTemplate(templateData)

internal/controller/httproute.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package controller
22

33
import (
44
"context"
5+
"fmt"
56
"strings"
67

78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
10+
"k8s.io/apimachinery/pkg/runtime"
811
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
912

1013
"github.com/home-operations/gatus-sidecar/internal/config"
14+
"github.com/home-operations/gatus-sidecar/internal/endpoint"
1115
"github.com/home-operations/gatus-sidecar/internal/handler"
12-
"github.com/home-operations/gatus-sidecar/internal/state"
16+
"github.com/home-operations/gatus-sidecar/internal/manager"
1317
)
1418

1519
// HTTPRouteHandler handles HTTPRoute resources
@@ -45,18 +49,40 @@ func (h *HTTPRouteHandler) ExtractURL(obj metav1.Object) string {
4549
if !strings.HasPrefix(url, "http") {
4650
url = "https://" + url
4751
}
52+
4853
return url
4954
}
5055

5156
func (h *HTTPRouteHandler) GetResourceName() string {
5257
return "route"
5358
}
5459

60+
func (h *HTTPRouteHandler) ApplyTemplate(cfg *config.Config, obj metav1.Object, endpoint *endpoint.Endpoint) bool {
61+
if cfg.AutoGroup {
62+
route, ok := obj.(*gatewayv1.HTTPRoute)
63+
if !ok {
64+
return false
65+
}
66+
67+
// If there are no ParentRefs, cannot group
68+
if len(route.Spec.ParentRefs) == 0 {
69+
return false
70+
}
71+
72+
// Group by the first ParentRef (gateway) name
73+
endpoint.Group = string(route.Spec.ParentRefs[0].Name)
74+
return true
75+
}
76+
77+
return false
78+
}
79+
5580
// Helper functions for HTTPRoute
5681
func firstHTTPRouteHostname(route *gatewayv1.HTTPRoute) string {
5782
for _, h := range route.Spec.Hostnames {
5883
return string(h)
5984
}
85+
6086
return ""
6187
}
6288

@@ -66,11 +92,28 @@ func referencesGateway(route *gatewayv1.HTTPRoute, gatewayName string) bool {
6692
return true
6793
}
6894
}
95+
6996
return false
7097
}
7198

99+
// NewHTTPRouteController creates a controller for HTTPRoute resources
100+
func NewHTTPRouteController(resourceHandler handler.ResourceHandler, stateManager *manager.Manager) *Controller {
101+
return &Controller{
102+
gvr: gatewayv1.SchemeGroupVersion.WithResource("httproutes"),
103+
handler: resourceHandler,
104+
stateManager: stateManager,
105+
convert: func(u *unstructured.Unstructured) (metav1.Object, error) {
106+
route := &gatewayv1.HTTPRoute{}
107+
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, route); err != nil {
108+
return nil, fmt.Errorf("failed to convert to HTTPRoute: %w", err)
109+
}
110+
return route, nil
111+
},
112+
}
113+
}
114+
72115
func RunHTTPRoute(ctx context.Context, cfg *config.Config) error {
73-
stateManager := state.NewManager(cfg.Output)
116+
stateManager := manager.NewManager(cfg.Output)
74117
handler := &HTTPRouteHandler{}
75118
ctrl := NewHTTPRouteController(handler, stateManager)
76119
return ctrl.Run(ctx, cfg)

internal/controller/ingress.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ import (
88

99
networkingv1 "k8s.io/api/networking/v1"
1010
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12+
"k8s.io/apimachinery/pkg/runtime"
13+
"k8s.io/apimachinery/pkg/runtime/schema"
1114

1215
"github.com/home-operations/gatus-sidecar/internal/config"
16+
"github.com/home-operations/gatus-sidecar/internal/endpoint"
1317
"github.com/home-operations/gatus-sidecar/internal/handler"
14-
"github.com/home-operations/gatus-sidecar/internal/state"
18+
"github.com/home-operations/gatus-sidecar/internal/manager"
1519
)
1620

1721
// IngressHandler handles Ingress resources
@@ -29,6 +33,7 @@ func (h *IngressHandler) ShouldProcess(obj metav1.Object, cfg *config.Config) bo
2933
if cfg.IngressClass != "" && !hasIngressClass(ingress, cfg.IngressClass) {
3034
return false
3135
}
36+
3237
return true
3338
}
3439

@@ -52,20 +57,43 @@ func (h *IngressHandler) ExtractURL(obj metav1.Object) string {
5257
if !strings.HasPrefix(url, "http") {
5358
url = fmt.Sprintf("%s://%s", protocol, url)
5459
}
60+
5561
return url
5662
}
5763

5864
func (h *IngressHandler) GetResourceName() string {
5965
return "ingress"
6066
}
6167

68+
func (h *IngressHandler) ApplyTemplate(cfg *config.Config, obj metav1.Object, endpoint *endpoint.Endpoint) bool {
69+
if cfg.AutoGroup {
70+
ingress, ok := obj.(*networkingv1.Ingress)
71+
if !ok {
72+
return false
73+
}
74+
75+
// Group by the first ParentRef (gateway) name
76+
ingressClass := getIngressClass(ingress)
77+
if ingressClass == "" {
78+
return false
79+
}
80+
81+
// Group by IngressClass
82+
endpoint.Group = ingressClass
83+
return true
84+
}
85+
86+
return false
87+
}
88+
6289
// Helper functions for Ingress
6390
func firstIngressHostname(ingress *networkingv1.Ingress) string {
6491
for _, rule := range ingress.Spec.Rules {
6592
if rule.Host != "" {
6693
return rule.Host
6794
}
6895
}
96+
6997
return ""
7098
}
7199

@@ -75,27 +103,52 @@ func hasIngressTLS(ingress *networkingv1.Ingress, hostname string) bool {
75103
return true
76104
}
77105
}
106+
78107
return false
79108
}
80109

81110
func hasIngressClass(ingress *networkingv1.Ingress, ingressClass string) bool {
111+
return getIngressClass(ingress) == ingressClass
112+
}
113+
114+
func getIngressClass(ingress *networkingv1.Ingress) string {
82115
// Check spec.ingressClassName first (preferred)
83-
if ingress.Spec.IngressClassName != nil && *ingress.Spec.IngressClassName == ingressClass {
84-
return true
116+
if ingress.Spec.IngressClassName != nil {
117+
return *ingress.Spec.IngressClassName
85118
}
86119

87120
// Fallback to annotation (legacy)
88121
if ingress.Annotations != nil {
89122
if class, ok := ingress.Annotations["kubernetes.io/ingress.class"]; ok {
90-
return class == ingressClass
123+
return class
91124
}
92125
}
93126

94-
return false
127+
return ""
128+
}
129+
130+
// NewIngressController creates a controller for Ingress resources
131+
func NewIngressController(resourceHandler handler.ResourceHandler, stateManager *manager.Manager) *Controller {
132+
return &Controller{
133+
gvr: schema.GroupVersionResource{
134+
Group: "networking.k8s.io",
135+
Version: "v1",
136+
Resource: "ingresses",
137+
},
138+
handler: resourceHandler,
139+
stateManager: stateManager,
140+
convert: func(u *unstructured.Unstructured) (metav1.Object, error) {
141+
ingress := &networkingv1.Ingress{}
142+
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, ingress); err != nil {
143+
return nil, fmt.Errorf("failed to convert to Ingress: %w", err)
144+
}
145+
return ingress, nil
146+
},
147+
}
95148
}
96149

97150
func RunIngress(ctx context.Context, cfg *config.Config) error {
98-
stateManager := state.NewManager(cfg.Output)
151+
stateManager := manager.NewManager(cfg.Output)
99152
handler := &IngressHandler{}
100153
ctrl := NewIngressController(handler, stateManager)
101154
return ctrl.Run(ctx, cfg)

0 commit comments

Comments
 (0)