Skip to content

Commit 420e099

Browse files
author
Kate Osborn
committed
Add support for multiple backends and weight in state package
1 parent 95fd648 commit 420e099

12 files changed

+1414
-646
lines changed

internal/state/backend_group.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package state
2+
3+
import (
4+
"fmt"
5+
6+
"k8s.io/apimachinery/pkg/types"
7+
)
8+
9+
// BackendGroup represents a group of backends for a rule in an HTTPRoute.
10+
type BackendGroup struct {
11+
Source types.NamespacedName
12+
RuleIdx int
13+
Backends []BackendRef
14+
}
15+
16+
// BackendRef is an internal representation of a backendRef in an HTTPRoute.
17+
type BackendRef struct {
18+
Name string
19+
Valid bool
20+
Weight int32
21+
}
22+
23+
// NeedsSplit returns true if traffic needs to be split among the backends in the group.
24+
func (bg *BackendGroup) NeedsSplit() bool {
25+
return len(bg.Backends) > 1
26+
}
27+
28+
// Name returns the name of the backend group.
29+
// If the group needs to be split, the name returned is the name of the group.
30+
// If the group doesn't need to be split, the name returned is the name of the backend if it is valid.
31+
// If the name cannot be determined, it returns an empty string.
32+
func (bg *BackendGroup) Name() string {
33+
switch len(bg.Backends) {
34+
case 0:
35+
return ""
36+
case 1:
37+
b := bg.Backends[0]
38+
if b.Weight <= 0 || !b.Valid {
39+
return ""
40+
}
41+
return b.Name
42+
default:
43+
return bg.GroupName()
44+
}
45+
}
46+
47+
// GroupName returns the name of the backend group.
48+
func (bg *BackendGroup) GroupName() string {
49+
return fmt.Sprintf("%s_%s_rule%d", bg.Source.Namespace, bg.Source.Name, bg.RuleIdx)
50+
}

internal/state/backend_group_test.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package state_test
2+
3+
import (
4+
"testing"
5+
6+
"k8s.io/apimachinery/pkg/types"
7+
8+
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state"
9+
)
10+
11+
func TestBackendGroup_NeedsSplit(t *testing.T) {
12+
tests := []struct {
13+
msg string
14+
backends []state.BackendRef
15+
expSplit bool
16+
}{
17+
{
18+
msg: "empty backends",
19+
backends: []state.BackendRef{},
20+
expSplit: false,
21+
},
22+
{
23+
msg: "nil backends",
24+
backends: nil,
25+
expSplit: false,
26+
},
27+
{
28+
msg: "one valid backend",
29+
backends: []state.BackendRef{
30+
{
31+
Name: "backend1",
32+
Valid: true,
33+
Weight: 1,
34+
},
35+
},
36+
expSplit: false,
37+
},
38+
{
39+
msg: "one invalid backend",
40+
backends: []state.BackendRef{
41+
{
42+
Name: "backend1",
43+
Valid: false,
44+
Weight: 1,
45+
},
46+
},
47+
expSplit: false,
48+
},
49+
{
50+
msg: "multiple valid backends",
51+
backends: []state.BackendRef{
52+
{
53+
Name: "backend1",
54+
Valid: true,
55+
Weight: 1,
56+
},
57+
{
58+
Name: "backend2",
59+
Valid: true,
60+
Weight: 1,
61+
},
62+
},
63+
expSplit: true,
64+
},
65+
{
66+
msg: "multiple backends - one invalid",
67+
backends: []state.BackendRef{
68+
{
69+
Name: "backend1",
70+
Valid: true,
71+
Weight: 1,
72+
},
73+
{
74+
Name: "backend2",
75+
Valid: false,
76+
Weight: 1,
77+
},
78+
},
79+
expSplit: true,
80+
},
81+
}
82+
83+
for _, test := range tests {
84+
bg := state.BackendGroup{
85+
Source: types.NamespacedName{Namespace: "test", Name: "hr"},
86+
Backends: test.backends,
87+
}
88+
result := bg.NeedsSplit()
89+
if result != test.expSplit {
90+
t.Errorf("BackendGroup.NeedsSplit() mismatch for %q; expected %t", test.msg, result)
91+
}
92+
}
93+
}
94+
95+
func TestBackendGroup_Name(t *testing.T) {
96+
tests := []struct {
97+
msg string
98+
backends []state.BackendRef
99+
expName string
100+
}{
101+
{
102+
msg: "empty backends",
103+
backends: []state.BackendRef{},
104+
expName: "",
105+
},
106+
{
107+
msg: "nil backends",
108+
backends: nil,
109+
expName: "",
110+
},
111+
{
112+
msg: "one valid backend with non-zero weight",
113+
backends: []state.BackendRef{
114+
{
115+
Name: "backend1",
116+
Valid: true,
117+
Weight: 1,
118+
},
119+
},
120+
expName: "backend1",
121+
},
122+
{
123+
msg: "one valid backend with zero weight",
124+
backends: []state.BackendRef{
125+
{
126+
Name: "backend1",
127+
Valid: true,
128+
Weight: 0,
129+
},
130+
},
131+
expName: "",
132+
},
133+
{
134+
msg: "one invalid backend",
135+
backends: []state.BackendRef{
136+
{
137+
Name: "backend1",
138+
Valid: false,
139+
Weight: 1,
140+
},
141+
},
142+
expName: "",
143+
},
144+
{
145+
msg: "multiple valid backends",
146+
backends: []state.BackendRef{
147+
{
148+
Name: "backend1",
149+
Valid: true,
150+
Weight: 1,
151+
},
152+
{
153+
Name: "backend2",
154+
Valid: true,
155+
Weight: 1,
156+
},
157+
},
158+
expName: "test_hr_rule0",
159+
},
160+
{
161+
msg: "multiple invalid backends",
162+
backends: []state.BackendRef{
163+
{
164+
Name: "backend1",
165+
Valid: false,
166+
Weight: 1,
167+
},
168+
{
169+
Name: "backend2",
170+
Valid: false,
171+
Weight: 1,
172+
},
173+
},
174+
expName: "test_hr_rule0",
175+
},
176+
}
177+
178+
for _, test := range tests {
179+
bg := state.BackendGroup{
180+
Source: types.NamespacedName{Namespace: "test", Name: "hr"},
181+
RuleIdx: 0,
182+
Backends: test.backends,
183+
}
184+
result := bg.Name()
185+
if result != test.expName {
186+
t.Errorf("BackendGroup.Name() mismatch for %q; expected %s, got %s", test.msg, test.expName, result)
187+
}
188+
}
189+
}
190+
191+
func TestBackendGroup_GroupName(t *testing.T) {
192+
bg := state.BackendGroup{
193+
Source: types.NamespacedName{Namespace: "test", Name: "hr"},
194+
RuleIdx: 20,
195+
}
196+
expected := "test_hr_rule20"
197+
result := bg.GroupName()
198+
if result != expected {
199+
t.Errorf("BackendGroup.GroupName() mismatch; expected %s, got %s", expected, result)
200+
}
201+
}

0 commit comments

Comments
 (0)