From 99f75c1008f08d439e9dc44cf2f9f8b0ab725732 Mon Sep 17 00:00:00 2001 From: Olivier Duclos Date: Wed, 29 Nov 2023 21:26:43 +0100 Subject: [PATCH] MINOR: Add TCP session attribute attach-srv --- configuration/configuration_test.go | 3 + configuration/tcp_request_rule.go | 15 ++++ configuration/tcp_request_rule_test.go | 76 +++++++++++++++++-- go.mod | 2 +- go.sum | 4 +- models/tcp_request_rule.go | 10 ++- models/tcp_request_rule_compare.go | 8 ++ models/tcp_request_rule_compare_test.go | 4 +- specification/build/haproxy_spec.yaml | 10 +++ .../models/configuration/tcp/request.yaml | 11 ++- 10 files changed, 130 insertions(+), 13 deletions(-) diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go index 19518648..8da69f06 100644 --- a/configuration/configuration_test.go +++ b/configuration/configuration_test.go @@ -494,6 +494,9 @@ frontend test tcp-request content track-sc5 src table test if TRUE tcp-request connection track-sc5 src table test if TRUE tcp-request session track-sc5 src table test if TRUE + tcp-request session attach-srv srv1 + tcp-request session attach-srv srv2 name example.com + tcp-request session attach-srv srv3 if is_cached log global no log log 127.0.0.1:514 local0 notice notice diff --git a/configuration/tcp_request_rule.go b/configuration/tcp_request_rule.go index e8dd9691..8edd407a 100644 --- a/configuration/tcp_request_rule.go +++ b/configuration/tcp_request_rule.go @@ -532,6 +532,12 @@ func ParseTCPRequestRule(f types.TCPType) (rule *models.TCPRequestRule, err erro rule.Action = models.TCPRequestRuleActionAccept rule.Cond = a.Cond rule.CondTest = a.CondTest + case *tcp_actions.AttachSrv: + rule.Action = models.TCPRequestRuleActionAttachDashSrv + rule.ServerName = a.Server + rule.Expr = a.Name.String() + rule.Cond = a.Cond + rule.CondTest = a.CondTest case *actions.Reject: rule.Action = models.TCPRequestRuleActionAccept rule.Cond = a.Cond @@ -1077,6 +1083,15 @@ func SerializeTCPRequestRule(f models.TCPRequestRule) (rule types.TCPType, err e CondTest: f.CondTest, }, }, nil + case models.TCPRequestRuleActionAttachDashSrv: + return &tcp_types.Session{ + Action: &tcp_actions.AttachSrv{ + Server: f.ServerName, + Name: common.Expression{Expr: []string{f.Expr}}, + Cond: f.Cond, + CondTest: f.CondTest, + }, + }, nil case models.TCPRequestRuleActionReject: return &tcp_types.Session{ Action: &actions.Reject{ diff --git a/configuration/tcp_request_rule_test.go b/configuration/tcp_request_rule_test.go index 53b07f0c..0227bda0 100644 --- a/configuration/tcp_request_rule_test.go +++ b/configuration/tcp_request_rule_test.go @@ -30,8 +30,8 @@ func TestGetTCPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo t.Error(err.Error()) } - if len(tRules) != 30 { - t.Errorf("%v tcp request rules returned, expected 30", len(tRules)) + if len(tRules) != 33 { + t.Errorf("%v tcp request rules returned, expected 33", len(tRules)) } if v != version { @@ -566,6 +566,45 @@ func TestGetTCPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "TRUE" { t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest) } + case 30: + if r.Type != "session" { + t.Errorf("%v: Type not session: %v", *r.Index, r.Type) + } + if r.Action != "attach-srv" { + t.Errorf("%v: Action not attach-srv: %v", *r.Index, r.Action) + } + if r.ServerName != "srv1" { + t.Errorf("%v: ServerName not srv1: %v", *r.Index, r.ServerName) + } + case 31: + if r.Type != "session" { + t.Errorf("%v: Type not session: %v", *r.Index, r.Type) + } + if r.Action != "attach-srv" { + t.Errorf("%v: Action not attach-srv: %v", *r.Index, r.Action) + } + if r.ServerName != "srv2" { + t.Errorf("%v: ServerName not srv2: %v", *r.Index, r.ServerName) + } + if r.Expr != "example.com" { + t.Errorf("%v: Expr not example.com: %v", *r.Index, r.Expr) + } + case 32: + if r.Type != "session" { + t.Errorf("%v: Type not session: %v", *r.Index, r.Type) + } + if r.Action != "attach-srv" { + t.Errorf("%v: Action not attach-srv: %v", *r.Index, r.Action) + } + if r.ServerName != "srv3" { + t.Errorf("%v: ServerName not srv1: %v", *r.Index, r.ServerName) + } + if r.Cond != "if" { + t.Errorf("%v: Cond is not if: %v", *r.Index, r.Cond) + } + if r.CondTest != "is_cached" { + t.Errorf("%v: CondTest not is_cached: %v", *r.Index, r.CondTest) + } default: t.Errorf("Expect tcp-request 0-26, %v found", *r.Index) } @@ -678,7 +717,7 @@ func TestCreateEditDeleteTCPRequestRule(t *testing.T) { } // TestDeleteTCPRequest - err = clientTest.DeleteTCPRequestRule(30, "frontend", "test", "", version) + err = clientTest.DeleteTCPRequestRule(33, "frontend", "test", "", version) if err != nil { t.Error(err.Error()) } else { @@ -689,9 +728,9 @@ func TestCreateEditDeleteTCPRequestRule(t *testing.T) { t.Error("Version not incremented") } - _, _, err = clientTest.GetTCPRequestRule(30, "frontend", "test", "") + _, _, err = clientTest.GetTCPRequestRule(33, "frontend", "test", "") if err == nil { - t.Error("DeleteTCPRequestRule failed, TCP Request Rule 30 still exists") + t.Error("DeleteTCPRequestRule failed, TCP Request Rule 33 still exists") } err = clientTest.DeleteTCPRequestRule(27, "backend", "test_2", "", version) @@ -877,6 +916,33 @@ func TestSerializeTCPRequestRule(t *testing.T) { }, expectedResult: "session track-sc2 src table tr2 if TRUE", }, + { + input: models.TCPRequestRule{ + Type: models.TCPRequestRuleTypeSession, + Action: models.TCPRequestRuleActionAttachDashSrv, + ServerName: "srv8", + Expr: "haproxy.org", + }, + expectedResult: "session attach-srv srv8 name haproxy.org", + }, + { + input: models.TCPRequestRule{ + Type: models.TCPRequestRuleTypeSession, + Action: models.TCPRequestRuleActionAttachDashSrv, + ServerName: "srv8", + }, + expectedResult: "session attach-srv srv8", + }, + { + input: models.TCPRequestRule{ + Type: models.TCPRequestRuleTypeSession, + Action: models.TCPRequestRuleActionAttachDashSrv, + ServerName: "srv8", + Cond: "unless", + CondTest: "limit_exceeded", + }, + expectedResult: "session attach-srv srv8 unless limit_exceeded", + }, } for _, testCase := range testCases { diff --git a/go.mod b/go.mod index c22463bb..1aefe025 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/renameio v1.0.1 github.com/google/uuid v1.3.1 - github.com/haproxytech/config-parser/v5 v5.0.1-0.20231130162059-22edd103d783 + github.com/haproxytech/config-parser/v5 v5.0.1-0.20231204090448-72b7eafd24a7 github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 6ac4b25a..f5110978 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWU github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/haproxytech/config-parser/v5 v5.0.1-0.20231130162059-22edd103d783 h1:wTilFGOhN6TilltUL4OK5wjg+RsLyCVLScP0flaU6+w= -github.com/haproxytech/config-parser/v5 v5.0.1-0.20231130162059-22edd103d783/go.mod h1:ASOyT1KguwXaY0NfoLNjLLs0OlnYHnFgUJsdJe6NhZg= +github.com/haproxytech/config-parser/v5 v5.0.1-0.20231204090448-72b7eafd24a7 h1:rCgSKbeF3Sr4hA2wQ2geuRzTj9ZvHdzI2bmHXneEtD8= +github.com/haproxytech/config-parser/v5 v5.0.1-0.20231204090448-72b7eafd24a7/go.mod h1:ASOyT1KguwXaY0NfoLNjLLs0OlnYHnFgUJsdJe6NhZg= github.com/haproxytech/go-logger v1.1.0 h1:HgGtYaI1ApkvbQdsm7f9AzQQoxTB7w37criTflh7IQE= github.com/haproxytech/go-logger v1.1.0/go.mod h1:OekUd8HCb7ubxMplzHUPBTHNxZmddOWfOjWclZsqIeM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= diff --git a/models/tcp_request_rule.go b/models/tcp_request_rule.go index a5d87af6..37b5f806 100644 --- a/models/tcp_request_rule.go +++ b/models/tcp_request_rule.go @@ -39,7 +39,7 @@ import ( type TCPRequestRule struct { // action - // Enum: [accept capture do-resolve expect-netscaler-cip expect-proxy reject sc-add-gpc sc-inc-gpc sc-inc-gpc0 sc-inc-gpc1 sc-set-gpt0 send-spoe-group set-dst-port set-dst set-priority set-src set-var silent-drop track-sc0 track-sc1 track-sc2 track-sc unset-var use-service lua set-bandwidth-limit set-src-port set-mark set-tos set-var-fmt set-log-level set-nice switch-mode] + // Enum: [accept attach-srv capture do-resolve expect-netscaler-cip expect-proxy reject sc-add-gpc sc-inc-gpc sc-inc-gpc0 sc-inc-gpc1 sc-set-gpt0 send-spoe-group set-dst-port set-dst set-priority set-src set-var silent-drop track-sc0 track-sc1 track-sc2 track-sc unset-var use-service lua set-bandwidth-limit set-src-port set-mark set-tos set-var-fmt set-log-level set-nice switch-mode] Action string `json:"action,omitempty"` // bandwidth limit limit @@ -118,6 +118,9 @@ type TCPRequestRule struct { // sc int ScInt *int64 `json:"sc_int,omitempty"` + // server name + ServerName string `json:"server_name,omitempty"` + // service name ServiceName string `json:"service_name,omitempty"` @@ -233,7 +236,7 @@ var tcpRequestRuleTypeActionPropEnum []interface{} func init() { var res []string - if err := json.Unmarshal([]byte(`["accept","capture","do-resolve","expect-netscaler-cip","expect-proxy","reject","sc-add-gpc","sc-inc-gpc","sc-inc-gpc0","sc-inc-gpc1","sc-set-gpt0","send-spoe-group","set-dst-port","set-dst","set-priority","set-src","set-var","silent-drop","track-sc0","track-sc1","track-sc2","track-sc","unset-var","use-service","lua","set-bandwidth-limit","set-src-port","set-mark","set-tos","set-var-fmt","set-log-level","set-nice","switch-mode"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["accept","attach-srv","capture","do-resolve","expect-netscaler-cip","expect-proxy","reject","sc-add-gpc","sc-inc-gpc","sc-inc-gpc0","sc-inc-gpc1","sc-set-gpt0","send-spoe-group","set-dst-port","set-dst","set-priority","set-src","set-var","silent-drop","track-sc0","track-sc1","track-sc2","track-sc","unset-var","use-service","lua","set-bandwidth-limit","set-src-port","set-mark","set-tos","set-var-fmt","set-log-level","set-nice","switch-mode"]`), &res); err != nil { panic(err) } for _, v := range res { @@ -246,6 +249,9 @@ const ( // TCPRequestRuleActionAccept captures enum value "accept" TCPRequestRuleActionAccept string = "accept" + // TCPRequestRuleActionAttachDashSrv captures enum value "attach-srv" + TCPRequestRuleActionAttachDashSrv string = "attach-srv" + // TCPRequestRuleActionCapture captures enum value "capture" TCPRequestRuleActionCapture string = "capture" diff --git a/models/tcp_request_rule_compare.go b/models/tcp_request_rule_compare.go index 225d3a08..834505eb 100644 --- a/models/tcp_request_rule_compare.go +++ b/models/tcp_request_rule_compare.go @@ -125,6 +125,10 @@ func (s TCPRequestRule) Equal(t TCPRequestRule, opts ...Options) bool { return false } + if s.ServerName != t.ServerName { + return false + } + if s.ServiceName != t.ServiceName { return false } @@ -289,6 +293,10 @@ func (s TCPRequestRule) Diff(t TCPRequestRule, opts ...Options) map[string][]int diff["ScInt"] = []interface{}{ValueOrNil(s.ScInt), ValueOrNil(t.ScInt)} } + if s.ServerName != t.ServerName { + diff["ServerName"] = []interface{}{s.ServerName, t.ServerName} + } + if s.ServiceName != t.ServiceName { diff["ServiceName"] = []interface{}{s.ServiceName, t.ServiceName} } diff --git a/models/tcp_request_rule_compare_test.go b/models/tcp_request_rule_compare_test.go index c4b398ce..03c5c0e3 100644 --- a/models/tcp_request_rule_compare_test.go +++ b/models/tcp_request_rule_compare_test.go @@ -181,7 +181,7 @@ func TestTCPRequestRuleDiffFalse(t *testing.T) { for _, sample := range samples { result := sample.a.Diff(sample.b) - if len(result) != 36-1 { + if len(result) != 37-1 { json := jsoniter.ConfigCompatibleWithStandardLibrary a, err := json.Marshal(&sample.a) if err != nil { @@ -191,7 +191,7 @@ func TestTCPRequestRuleDiffFalse(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - t.Errorf("Expected TCPRequestRule to be different in 36 cases, but it is not (%d) %s %s", len(result), a, b) + t.Errorf("Expected TCPRequestRule to be different in 37 cases, but it is not (%d) %s %s", len(result), a, b) } } } diff --git a/specification/build/haproxy_spec.yaml b/specification/build/haproxy_spec.yaml index 73035e08..33446c78 100644 --- a/specification/build/haproxy_spec.yaml +++ b/specification/build/haproxy_spec.yaml @@ -5617,6 +5617,7 @@ definitions: action: enum: - accept + - attach-srv - capture - do-resolve - expect-netscaler-cip @@ -5923,6 +5924,15 @@ definitions: - sc-set-gpt0 x-display-name: ScSet Integer Value x-nullable: true + server_name: + type: string + x-dependency: + action: + required: true + value: attach-srv + type: + value: session + x-display-name: Server name service_name: type: string x-dependency: diff --git a/specification/models/configuration/tcp/request.yaml b/specification/models/configuration/tcp/request.yaml index e129b79a..5200f632 100644 --- a/specification/models/configuration/tcp/request.yaml +++ b/specification/models/configuration/tcp/request.yaml @@ -16,7 +16,7 @@ tcp_request_rule: x-nullable: false action: type: string - enum: [accept, capture, do-resolve, expect-netscaler-cip, expect-proxy, reject, sc-add-gpc, sc-inc-gpc, sc-inc-gpc0, sc-inc-gpc1, sc-set-gpt0, send-spoe-group, set-dst-port, set-dst, set-priority, set-src, set-var, silent-drop, track-sc0, track-sc1, track-sc2, track-sc, unset-var, use-service, lua, set-bandwidth-limit, set-src-port, set-mark, set-tos, set-var-fmt, set-log-level, set-nice, switch-mode] + enum: [accept, attach-srv, capture, do-resolve, expect-netscaler-cip, expect-proxy, reject, sc-add-gpc, sc-inc-gpc, sc-inc-gpc0, sc-inc-gpc1, sc-set-gpt0, send-spoe-group, set-dst-port, set-dst, set-priority, set-src, set-var, silent-drop, track-sc0, track-sc1, track-sc2, track-sc, unset-var, use-service, lua, set-bandwidth-limit, set-src-port, set-mark, set-tos, set-var-fmt, set-log-level, set-nice, switch-mode] x-nullable: false x-dependency: type: @@ -207,6 +207,15 @@ tcp_request_rule: required: true type: value: content + server_name: + type: string + x-display-name: Server name + x-dependency: + action: + value: attach-srv + required: true + type: + value: session timeout: type: integer x-nullable: true