Skip to content

Commit 0315787

Browse files
Header based routing (#144)
* Add parsing header-match rule from HTTPRoute object * Fix existing unit tests * Snapshot the parse header match code * Update and add name * Add rule matching based on header * Update logic to handle multiple headers matching and path * Return error if parse rule failed * Update the rule comparasion logic so that header-based stale rule can be deleted * Bug fix for matching path EXAT or PREFIX logic * fix fmt format issue * Update debug msgs * Remove generic RuleType, RuleValue from RuleSpec * Fix existing unit test * Add 1st rule test * Add pathbased match test cases * Add mismatch path related rule unit test * Add 1st header based match * Add header based rule build * Remove mismatch rule tests * Add more test * Add more tests * Add more test * Add negative test * Add more test * Add negatitie test cases * Create a common rule comparasion routine and fix the current manager unit test * Follow golang code style * Refactor and have same routine for httpRouteMatch for create and update API * Update unittest and debug msgs * Update loglevel * refactor the code to common routine * Removed unused code (after the refactor) * Fix unit test failures * UPdate debug msg * Re-add back the unit test * Update the log level * Add header based unit test * Remove commented code * Add rule update unit test for header-based rule * Add some more tests * Add initial rule comparasion unit test * Add 1st rule comparasion unit test * Add more headers unit test cases * Add more unit test * Add negative test for rule match * Add more unit tests and fix one bug * make sure header based always being populated
1 parent d17620f commit 0315787

File tree

12 files changed

+1886
-133
lines changed

12 files changed

+1886
-133
lines changed

controllers/httproute_controller.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ func (r *HTTPRouteReconciler) updateHTTPRouteStatus(ctx context.Context, dns str
288288
httproute.Status.RouteStatus.Parents[0].Conditions[0].LastTransitionTime = eventhandlers.ZeroTransitionTime
289289
}
290290

291-
fmt.Printf("liwwu >>>>httproute :%v \n", httproute)
292291
httproute.Status.RouteStatus.Parents[0].ControllerName = config.LatticeGatewayControllerName
293292

294293
httproute.Status.RouteStatus.Parents[0].Conditions[0].Type = "httproute"

pkg/deploy/lattice/rule_manager.go

Lines changed: 155 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (r *defaultRuleManager) Update(ctx context.Context, rules []*latticemodel.R
9696

9797
if err != nil {
9898
errmsg := fmt.Sprintf("Service %v not found during rule creation", rules[0].Spec)
99-
glog.V(6).Infof("Error during update rule %s \n", errmsg)
99+
glog.V(2).Infof("Error during update rule %s \n", errmsg)
100100
return errors.New(errmsg)
101101
}
102102

@@ -105,7 +105,7 @@ func (r *defaultRuleManager) Update(ctx context.Context, rules []*latticemodel.R
105105

106106
if err != nil {
107107
errmsg := fmt.Sprintf("Listener %v not found during rule creation", rules[0].Spec)
108-
glog.V(6).Infof("Error during update rule %s \n", errmsg)
108+
glog.V(2).Infof("Error during update rule %s \n", errmsg)
109109
return errors.New(errmsg)
110110
}
111111

@@ -143,7 +143,7 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
143143

144144
if err != nil {
145145
errmsg := fmt.Sprintf("Service %v not found during rule creation", rule.Spec)
146-
glog.V(6).Infof("Error during create rule %s \n", errmsg)
146+
glog.V(2).Infof("Error during create rule %s \n", errmsg)
147147
return latticemodel.RuleStatus{}, errors.New(errmsg)
148148
}
149149

@@ -152,15 +152,15 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
152152

153153
if err != nil {
154154
errmsg := fmt.Sprintf("Listener %v not found during rule creation", rule.Spec)
155-
glog.V(6).Infof("Error during create rule %s \n", errmsg)
155+
glog.V(2).Infof("Error during create rule %s \n", errmsg)
156156
return latticemodel.RuleStatus{}, errors.New(errmsg)
157157
}
158158

159159
priority, err := ruleID2Priority(rule.Spec.RuleID)
160160
glog.V(6).Infof("Convert rule id %s to priority %d error: %v \n", rule.Spec.RuleID, priority, err)
161161

162162
if err != nil {
163-
glog.V(6).Infof("Error create rule, failed to convert RuleID %v to priority err :%v\n", rule.Spec.RuleID, err)
163+
glog.V(2).Infof("Error create rule, failed to convert RuleID %v to priority err :%v\n", rule.Spec.RuleID, err)
164164
return latticemodel.RuleStatus{}, errors.New("failed to create rule, due to invalid ruleID")
165165
}
166166

@@ -186,14 +186,13 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
186186
tg, err := r.latticeDataStore.GetTargetGroup(tgName, tgRule.IsServiceImport)
187187

188188
if err != nil {
189-
glog.V(6).Infof("Faild to create rule due to unknown tg %v, err %v\n", tgName, err)
189+
glog.V(2).Infof("Faild to create rule due to unknown tg %v, err %v\n", tgName, err)
190190
return latticemodel.RuleStatus{}, err
191191
}
192192

193193
latticeTG := vpclattice.WeightedTargetGroup{
194194
TargetGroupIdentifier: aws.String(tg.ID),
195-
// TODO weighted target
196-
Weight: aws.Int64(tgRule.Weight),
195+
Weight: aws.Int64(tgRule.Weight),
197196
}
198197

199198
latticeTGs = append(latticeTGs, &latticeTG)
@@ -203,6 +202,10 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
203202
ruleName := fmt.Sprintf("k8s-%d-%s", rule.Spec.CreateTime.Unix(), rule.Spec.RuleID)
204203

205204
if ruleStatus.UpdateTGsNeeded {
205+
httpMatch := vpclattice.HttpMatch{}
206+
207+
updateSDKhttpMatch(&httpMatch, rule)
208+
206209
updateRuleInput := vpclattice.UpdateRuleInput{
207210
Action: &vpclattice.RuleAction{
208211
Forward: &vpclattice.ForwardAction{
@@ -211,15 +214,7 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
211214
},
212215
ListenerIdentifier: aws.String(listener.ID),
213216
Match: &vpclattice.RuleMatch{
214-
HttpMatch: &vpclattice.HttpMatch{
215-
PathMatch: &vpclattice.PathMatch{
216-
CaseSensitive: nil,
217-
Match: &vpclattice.PathMatchType{
218-
Exact: nil,
219-
Prefix: aws.String(rule.Spec.RuleValue),
220-
},
221-
},
222-
},
217+
HttpMatch: &httpMatch,
223218
},
224219
Priority: aws.Int64(ruleStatus.Priority),
225220
ServiceIdentifier: aws.String(latticeService.ID),
@@ -241,6 +236,10 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
241236

242237
} else {
243238

239+
httpMatch := vpclattice.HttpMatch{}
240+
241+
updateSDKhttpMatch(&httpMatch, rule)
242+
244243
ruleInput := vpclattice.CreateRuleInput{
245244
Action: &vpclattice.RuleAction{
246245
Forward: &vpclattice.ForwardAction{
@@ -250,15 +249,7 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
250249
ClientToken: nil,
251250
ListenerIdentifier: aws.String(listener.ID),
252251
Match: &vpclattice.RuleMatch{
253-
HttpMatch: &vpclattice.HttpMatch{
254-
PathMatch: &vpclattice.PathMatch{
255-
CaseSensitive: nil,
256-
Match: &vpclattice.PathMatchType{
257-
Exact: nil,
258-
Prefix: aws.String(rule.Spec.RuleValue),
259-
},
260-
},
261-
},
252+
HttpMatch: &httpMatch,
262253
},
263254
Name: aws.String(ruleName),
264255
Priority: aws.Int64(ruleStatus.Priority),
@@ -286,6 +277,135 @@ func (r *defaultRuleManager) Create(ctx context.Context, rule *latticemodel.Rule
286277

287278
}
288279

280+
func updateSDKhttpMatch(httpMatch *vpclattice.HttpMatch, rule *latticemodel.Rule) {
281+
glog.V(6).Infof("Setting sdk HttpMatch using rule.Spec %v", rule.Spec)
282+
283+
// setup path based
284+
if rule.Spec.PathMatchExact || rule.Spec.PathMatchPrefix {
285+
matchType := vpclattice.PathMatchType{}
286+
if rule.Spec.PathMatchExact {
287+
matchType.Exact = aws.String(rule.Spec.PathMatchValue)
288+
}
289+
if rule.Spec.PathMatchPrefix {
290+
matchType.Prefix = aws.String(rule.Spec.PathMatchValue)
291+
}
292+
293+
httpMatch.PathMatch = &vpclattice.PathMatch{
294+
Match: &matchType,
295+
}
296+
}
297+
298+
if rule.Spec.NumOfHeaderMatches > 0 {
299+
300+
for i := 0; i < rule.Spec.NumOfHeaderMatches; i++ {
301+
headerMatch := vpclattice.HeaderMatch{
302+
Match: rule.Spec.MatchedHeaders[i].Match,
303+
Name: rule.Spec.MatchedHeaders[i].Name,
304+
}
305+
httpMatch.HeaderMatches = append(httpMatch.HeaderMatches, &headerMatch)
306+
307+
}
308+
309+
}
310+
311+
}
312+
313+
func isRulesSame(modelRule *latticemodel.Rule, sdkRuleDetail *vpclattice.GetRuleOutput) bool {
314+
// Exact Path Match
315+
if modelRule.Spec.PathMatchExact {
316+
glog.V(6).Infoln("Checking PathMatchExact")
317+
318+
if sdkRuleDetail.Match.HttpMatch.PathMatch == nil ||
319+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match == nil ||
320+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Exact == nil {
321+
glog.V(6).Infoln("no sdk PathMatchExact match")
322+
return false
323+
}
324+
325+
if aws.StringValue(sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Exact) != modelRule.Spec.PathMatchValue {
326+
glog.V(6).Infoln("Match.Exact mismatch")
327+
return false
328+
}
329+
330+
} else {
331+
if sdkRuleDetail.Match.HttpMatch.PathMatch != nil &&
332+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match != nil &&
333+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Exact != nil {
334+
glog.V(6).Infoln("no sdk PathMatchExact match")
335+
return false
336+
}
337+
}
338+
339+
// Path Prefix
340+
if modelRule.Spec.PathMatchPrefix {
341+
glog.V(6).Infoln("Checking PathMatchPrefix")
342+
343+
if sdkRuleDetail.Match.HttpMatch.PathMatch == nil ||
344+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match == nil ||
345+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Prefix == nil {
346+
glog.V(6).Infoln("no sdk HTTP PathPrefix")
347+
return false
348+
}
349+
350+
if aws.StringValue(sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Prefix) != modelRule.Spec.PathMatchValue {
351+
glog.V(6).Infoln("PathMatchPrefix mismatch ")
352+
return false
353+
}
354+
} else {
355+
if sdkRuleDetail.Match.HttpMatch.PathMatch != nil &&
356+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match != nil &&
357+
sdkRuleDetail.Match.HttpMatch.PathMatch.Match.Prefix != nil {
358+
glog.V(6).Infoln("no sdk HTTP PathPrefix")
359+
return false
360+
}
361+
}
362+
363+
// Header Match
364+
365+
if modelRule.Spec.NumOfHeaderMatches > 0 {
366+
glog.V(6).Infof("Checking Header Match, numofheader matches %v \n", modelRule.Spec.NumOfHeaderMatches)
367+
if len(sdkRuleDetail.Match.HttpMatch.HeaderMatches) != modelRule.Spec.NumOfHeaderMatches {
368+
glog.V(6).Infoln("header match number mismatch")
369+
return false
370+
}
371+
372+
misMatch := false
373+
374+
// compare 2 array
375+
for _, sdkHeader := range sdkRuleDetail.Match.HttpMatch.HeaderMatches {
376+
glog.V(6).Infof("sdkHeader >> %v\n", sdkHeader)
377+
matchFound := false
378+
// check if this is in module
379+
for i := 0; i < modelRule.Spec.NumOfHeaderMatches; i++ {
380+
// compare header
381+
if aws.StringValue(modelRule.Spec.MatchedHeaders[i].Name) ==
382+
aws.StringValue(sdkHeader.Name) &&
383+
aws.StringValue(modelRule.Spec.MatchedHeaders[i].Match.Exact) ==
384+
aws.StringValue(sdkHeader.Match.Exact) {
385+
matchFound = true
386+
break
387+
}
388+
389+
}
390+
391+
if !matchFound {
392+
misMatch = true
393+
glog.V(6).Infof("header not found sdkHeader %v\n", *sdkHeader)
394+
break
395+
}
396+
}
397+
398+
if misMatch {
399+
glog.V(6).Infof("mismatch header")
400+
return false
401+
}
402+
}
403+
404+
return true
405+
}
406+
407+
// Determine if rule spec is same
408+
// If rule spec is same, then determine if there is any changes on target groups
289409
func (r *defaultRuleManager) findMatchingRule(ctx context.Context, rule *latticemodel.Rule,
290410
serviceID string, listenerID string) (latticemodel.RuleStatus, error) {
291411

@@ -336,32 +456,29 @@ func (r *defaultRuleManager) findMatchingRule(ctx context.Context, rule *lattice
336456
ruleResp, err := r.cloud.Lattice().GetRule(&ruleInput)
337457

338458
if err != nil {
339-
glog.V(6).Infof("findMatchingRule, rule %v not found err:%v\n", ruleInput, err)
459+
glog.V(2).Infof("findMatchingRule, rule %v not found err:%v\n", ruleInput, err)
340460
continue
341461
}
342462

343463
priorityMap[aws.Int64Value(ruleResp.Priority)] = true
344464

345-
// path based comparasion
465+
samerule := isRulesSame(rule, ruleResp)
346466

347-
if ruleResp.Match != nil && ruleResp.Match.HttpMatch.PathMatch != nil && aws.StringValue(ruleResp.Match.HttpMatch.PathMatch.Match.Prefix) != rule.Spec.RuleValue {
348-
glog.V(6).Infof("findMatchingRule, rule prefix %v does not match rule value %v\n",
349-
aws.StringValue(ruleResp.Match.HttpMatch.PathMatch.Match.Prefix), rule.Spec.RuleValue)
467+
if !samerule {
350468
continue
351-
352469
}
353470

354471
matchRule = ruleResp
355472

356473
if len(ruleResp.Action.Forward.TargetGroups) != len(rule.Spec.Action.TargetGroups) {
357-
glog.V(6).Infof("findMatchingRule, mismatch TGs lattice %v, k8s %v\n",
474+
glog.V(6).Infof("Mismatched TGs lattice %v, k8s %v\n",
358475
ruleResp.Action.Forward.TargetGroups, rule.Spec.Action.TargetGroups)
359476
updateTGsNeeded = true
360477
continue
361478
}
362479

363480
if len(ruleResp.Action.Forward.TargetGroups) == 0 {
364-
glog.V(6).Infof("findMatchingRule, 0 targetGroups \n")
481+
glog.V(6).Infof("0 targetGroups \n")
365482
continue
366483
}
367484

@@ -373,21 +490,21 @@ func (r *defaultRuleManager) findMatchingRule(ctx context.Context, rule *lattice
373490
k8sTGinStore, err := r.latticeDataStore.GetTargetGroup(tgName, k8sTG.IsServiceImport)
374491

375492
if err != nil {
376-
glog.V(6).Infof("findMatchingRule, failed to find tg %v in store \n", k8sTG)
493+
glog.V(6).Infof("Failed to find k8s tg %v in store \n", k8sTG)
377494
updateTGsNeeded = true
378495
continue
379496
}
380497

381498
if aws.StringValue(tg.TargetGroupIdentifier) != k8sTGinStore.ID {
382-
glog.V(6).Infof("findMatchingRule, failed to TGID mismatch lattice %v, k8s %v\n",
499+
glog.V(6).Infof("TGID mismatch lattice %v, k8s %v\n",
383500
aws.StringValue(tg.TargetGroupIdentifier), k8sTGinStore.ID)
384501
updateTGsNeeded = true
385502
continue
386503

387504
}
388505

389506
if k8sTG.Weight != aws.Int64Value(tg.Weight) {
390-
glog.V(6).Infof("findMatchRule, weight has changed for tg %v old %v new %v\n",
507+
glog.V(6).Infof("Weight has changed for tg %v old %v new %v\n",
391508
tg, aws.Int64Value(tg.Weight), k8sTG.Weight)
392509
updateTGsNeeded = true
393510
continue
@@ -398,7 +515,7 @@ func (r *defaultRuleManager) findMatchingRule(ctx context.Context, rule *lattice
398515
}
399516

400517
if updateTGsNeeded {
401-
glog.V(6).Infof("findMatchingRule: can not find matching TG tg %v in matching K8S tg\n", tg)
518+
glog.V(6).Infof("update TGs Needed for tg %v \n", tg)
402519
break
403520

404521
}

0 commit comments

Comments
 (0)