diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go index 6a796a9a..1c1e487d 100644 --- a/configuration/configuration_test.go +++ b/configuration/configuration_test.go @@ -403,6 +403,7 @@ frontend test http-request wait-for-body time 20s at-least 100k http-request set-timeout server 20 http-request set-timeout tunnel 20 + http-request set-timeout client 20 http-request set-bandwidth-limit my-limit limit 1m period 10s http-request set-bandwidth-limit my-limit-reverse period 20s limit 2m http-request set-bandwidth-limit my-limit-cond limit 3m if FALSE @@ -442,6 +443,9 @@ frontend test http-response track-sc1 src table tr1 if TRUE http-response track-sc2 src table tr2 if TRUE http-response track-sc5 src table test if TRUE + http-response set-timeout server 20 + http-response set-timeout tunnel 20 + http-response set-timeout client 20 http-after-response set-map(map.lst) %[src] %[res.hdr(X-Value)] http-after-response del-map(map.lst) %[src] if FALSE http-after-response del-acl(map.lst) %[src] if FALSE diff --git a/configuration/http_request_rule_test.go b/configuration/http_request_rule_test.go index 04774602..831c87be 100644 --- a/configuration/http_request_rule_test.go +++ b/configuration/http_request_rule_test.go @@ -30,8 +30,8 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo t.Error(err.Error()) } - if len(hRules) != 46 { - t.Errorf("%v http request rules returned, expected 46", len(hRules)) + if len(hRules) != 47 { + t.Errorf("%v http request rules returned, expected 47", len(hRules)) } if v != version { @@ -605,6 +605,16 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo t.Errorf("%v: Timeout not 20: %v", *r.Index, r.Timeout) } case 39: + if r.Type != "set-timeout" { + t.Errorf("%v: Type not set-timeout: %v", *r.Index, r.Type) + } + if r.TimeoutType != "client" { + t.Errorf("%v: TimeoutType not client: %v", *r.Index, r.TimeoutType) + } + if r.Timeout != "20" { + t.Errorf("%v: Timeout not 20: %v", *r.Index, r.Timeout) + } + case 40: if r.Type != "set-bandwidth-limit" { t.Errorf("%v: Type not set-bandwidth-limit: %v", *r.Index, r.Type) } @@ -617,7 +627,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.BandwidthLimitPeriod != "10s" { t.Errorf("%v: BandwidthLimitPeriod not 10s: %v", *r.Index, r.BandwidthLimitPeriod) } - case 40: + case 41: if r.Type != "set-bandwidth-limit" { t.Errorf("%v: Type not set-bandwidth-limit: %v", *r.Index, r.Type) } @@ -630,7 +640,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.BandwidthLimitPeriod != "20s" { t.Errorf("%v: BandwidthLimitPeriod no 20s: %v", *r.Index, r.BandwidthLimitPeriod) } - case 41: + case 42: if r.Type != "set-bandwidth-limit" { t.Errorf("%v: Type not set-bandwidth-limit: %v", *r.Index, r.Type) } @@ -649,7 +659,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "FALSE" { t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest) } - case 42: + case 43: if r.Type != "track-sc" { t.Errorf("%v: Type not track-sc: %v", *r.Index, r.Type) } @@ -668,7 +678,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "TRUE" { t.Errorf("%v: CondTest not TRUE: %v", *r.Index, r.CondTest) } - case 43: + case 44: if r.Type != "track-sc" { t.Errorf("%v: Type not track-sc: %v", *r.Index, r.Type) } @@ -687,7 +697,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "TRUE" { t.Errorf("%v: CondTest not TRUE: %v", *r.Index, r.CondTest) } - case 44: + case 45: if r.Type != "track-sc" { t.Errorf("%v: Type not track-sc: %v", *r.Index, r.Type) } @@ -706,7 +716,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "TRUE" { t.Errorf("%v: CondTest not TRUE: %v", *r.Index, r.CondTest) } - case 45: + case 46: if r.Type != "track-sc" { t.Errorf("%v: Type not track-sc: %v", *r.Index, r.Type) } @@ -726,7 +736,7 @@ func TestGetHTTPRequestRules(t *testing.T) { //nolint:gocognit,gocyclo t.Errorf("%v: CondTest not TRUE: %v", *r.Index, r.CondTest) } default: - t.Errorf("Expect only http-request 0 to 42, %v found", *r.Index) + t.Errorf("Expect only http-request 0 to 46, %v found", *r.Index) } } @@ -888,7 +898,7 @@ func TestCreateEditDeleteHTTPRequestRule(t *testing.T) { } // TestDeleteHTTPRequest - err = clientTest.DeleteHTTPRequestRule(46, "frontend", "test", "", version) + err = clientTest.DeleteHTTPRequestRule(47, "frontend", "test", "", version) if err != nil { t.Error(err.Error()) } else { @@ -899,9 +909,9 @@ func TestCreateEditDeleteHTTPRequestRule(t *testing.T) { t.Error("Version not incremented") } - _, _, err = clientTest.GetHTTPRequestRule(46, "frontend", "test", "") + _, _, err = clientTest.GetHTTPRequestRule(47, "frontend", "test", "") if err == nil { - t.Error("DeleteHTTPRequestRule failed, HTTP Request Rule 46 still exists") + t.Error("DeleteHTTPRequestRule failed, HTTP Request Rule 47 still exists") } err = clientTest.DeleteHTTPRequestRule(2, "backend", "test_2", "", version) diff --git a/configuration/http_response_rule.go b/configuration/http_response_rule.go index 5a3b5811..f0595331 100644 --- a/configuration/http_response_rule.go +++ b/configuration/http_response_rule.go @@ -456,6 +456,14 @@ func ParseHTTPResponseRule(f types.Action) *models.HTTPResponseRule { //nolint:m r.Status = status } return r + case *http_actions.SetTimeout: + return &models.HTTPResponseRule{ + Type: models.HTTPResponseRuleTypeSetDashTimeout, + Timeout: v.Timeout, + TimeoutType: v.Type, + Cond: v.Cond, + CondTest: v.CondTest, + } case *actions.SetTos: return &models.HTTPResponseRule{ Type: "set-tos", @@ -746,6 +754,13 @@ func SerializeHTTPResponseRule(f models.HTTPResponseRule) (rule types.Action, er Cond: f.Cond, CondTest: f.CondTest, } + case "set-timeout": + rule = &http_actions.SetTimeout{ + Timeout: f.Timeout, + Type: f.TimeoutType, + Cond: f.Cond, + CondTest: f.CondTest, + } case "set-tos": rule = &actions.SetTos{ Value: f.TosValue, diff --git a/configuration/http_response_rule_test.go b/configuration/http_response_rule_test.go index 7ebbd5e0..73341d56 100644 --- a/configuration/http_response_rule_test.go +++ b/configuration/http_response_rule_test.go @@ -30,8 +30,8 @@ func TestGetHTTPResponseRules(t *testing.T) { //nolint:gocognit,gocyclo t.Error(err.Error()) } - if len(hRules) != 32 { - t.Errorf("%v http response rules returned, expected 32", len(hRules)) + if len(hRules) != 35 { + t.Errorf("%v http response rules returned, expected 35", len(hRules)) } if v != version { @@ -529,8 +529,38 @@ func TestGetHTTPResponseRules(t *testing.T) { //nolint:gocognit,gocyclo if r.CondTest != "TRUE" { t.Errorf("%v: CondTest not TRUE: %v", *r.Index, r.CondTest) } + case 32: + if r.Type != "set-timeout" { + t.Errorf("%v: Type not set-timeout: %v", *r.Index, r.Type) + } + if r.TimeoutType != "server" { + t.Errorf("%v: TimeoutType not server: %v", *r.Index, r.TimeoutType) + } + if r.Timeout != "20" { + t.Errorf("%v: Timeout not 20: %v", *r.Index, r.Timeout) + } + case 33: + if r.Type != "set-timeout" { + t.Errorf("%v: Type not set-timeout: %v", *r.Index, r.Type) + } + if r.TimeoutType != "tunnel" { + t.Errorf("%v: TimeoutType not tunnel: %v", *r.Index, r.TimeoutType) + } + if r.Timeout != "20" { + t.Errorf("%v: Timeout not 20: %v", *r.Index, r.Timeout) + } + case 34: + if r.Type != "set-timeout" { + t.Errorf("%v: Type not set-timeout: %v", *r.Index, r.Type) + } + if r.TimeoutType != "client" { + t.Errorf("%v: TimeoutType not client: %v", *r.Index, r.TimeoutType) + } + if r.Timeout != "20" { + t.Errorf("%v: Timeout not 20: %v", *r.Index, r.Timeout) + } default: - t.Errorf("Expect only http-response 0 to 28, %v found", *r.Index) + t.Errorf("Expect only http-response 0 to 34, %v found", *r.Index) } } @@ -649,7 +679,7 @@ func TestCreateEditDeleteHTTPResponseRule(t *testing.T) { } // TestDeleteHTTPResponse - err = clientTest.DeleteHTTPResponseRule(32, "frontend", "test", "", version) + err = clientTest.DeleteHTTPResponseRule(35, "frontend", "test", "", version) if err != nil { t.Error(err.Error()) } else { @@ -660,9 +690,9 @@ func TestCreateEditDeleteHTTPResponseRule(t *testing.T) { t.Error("Version not incremented") } - _, _, err = clientTest.GetHTTPResponseRule(32, "frontend", "test", "") + _, _, err = clientTest.GetHTTPResponseRule(35, "frontend", "test", "") if err == nil { - t.Error("DeleteHTTPResponseRule failed, HTTPResponse Rule 32 still exists") + t.Error("DeleteHTTPResponseRule failed, HTTPResponse Rule 35 still exists") } err = clientTest.DeleteHTTPResponseRule(2, "backend", "test_2", "", version) diff --git a/models/http_request_rule.go b/models/http_request_rule.go index 2c9b07b1..b99991ae 100644 --- a/models/http_request_rule.go +++ b/models/http_request_rule.go @@ -241,7 +241,7 @@ type HTTPRequestRule struct { Timeout string `json:"timeout,omitempty"` // timeout type - // Enum: [server tunnel] + // Enum: [server tunnel client] TimeoutType string `json:"timeout_type,omitempty"` // tos value @@ -1188,7 +1188,7 @@ var httpRequestRuleTypeTimeoutTypePropEnum []interface{} func init() { var res []string - if err := json.Unmarshal([]byte(`["server","tunnel"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["server","tunnel","client"]`), &res); err != nil { panic(err) } for _, v := range res { @@ -1203,6 +1203,9 @@ const ( // HTTPRequestRuleTimeoutTypeTunnel captures enum value "tunnel" HTTPRequestRuleTimeoutTypeTunnel string = "tunnel" + + // HTTPRequestRuleTimeoutTypeClient captures enum value "client" + HTTPRequestRuleTimeoutTypeClient string = "client" ) // prop value enum diff --git a/models/http_response_rule.go b/models/http_response_rule.go index 947f0073..471e01df 100644 --- a/models/http_response_rule.go +++ b/models/http_response_rule.go @@ -192,6 +192,13 @@ type HTTPResponseRule struct { // Enum: [on off] StrictMode string `json:"strict_mode,omitempty"` + // timeout + Timeout string `json:"timeout,omitempty"` + + // timeout type + // Enum: [server tunnel client] + TimeoutType string `json:"timeout_type,omitempty"` + // tos value // Pattern: ^(0x[0-9A-Fa-f]+|[0-9]+)$ TosValue string `json:"tos_value,omitempty"` @@ -233,7 +240,7 @@ type HTTPResponseRule struct { // type // Required: true - // Enum: [add-acl add-header allow cache-store capture del-acl del-header del-map deny lua redirect replace-header replace-value return sc-add-gpc sc-inc-gpc sc-inc-gpc0 sc-inc-gpc1 sc-set-gpt0 send-spoe-group set-header set-log-level set-map set-mark set-nice set-status set-tos set-var set-var-fmt silent-drop strict-mode track-sc0 track-sc1 track-sc2 track-sc unset-var wait-for-body set-bandwidth-limit] + // Enum: [add-acl add-header allow cache-store capture del-acl del-header del-map deny lua redirect replace-header replace-value return sc-add-gpc sc-inc-gpc sc-inc-gpc0 sc-inc-gpc1 sc-set-gpt0 send-spoe-group set-header set-log-level set-map set-mark set-nice set-status set-timeout set-tos set-var set-var-fmt silent-drop strict-mode track-sc0 track-sc1 track-sc2 track-sc unset-var wait-for-body set-bandwidth-limit] Type string `json:"type"` // var expr @@ -357,6 +364,10 @@ func (m *HTTPResponseRule) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateTimeoutType(formats); err != nil { + res = append(res, err) + } + if err := m.validateTosValue(formats); err != nil { res = append(res, err) } @@ -936,6 +947,51 @@ func (m *HTTPResponseRule) validateStrictMode(formats strfmt.Registry) error { return nil } +var httpResponseRuleTypeTimeoutTypePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["server","tunnel","client"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + httpResponseRuleTypeTimeoutTypePropEnum = append(httpResponseRuleTypeTimeoutTypePropEnum, v) + } +} + +const ( + + // HTTPResponseRuleTimeoutTypeServer captures enum value "server" + HTTPResponseRuleTimeoutTypeServer string = "server" + + // HTTPResponseRuleTimeoutTypeTunnel captures enum value "tunnel" + HTTPResponseRuleTimeoutTypeTunnel string = "tunnel" + + // HTTPResponseRuleTimeoutTypeClient captures enum value "client" + HTTPResponseRuleTimeoutTypeClient string = "client" +) + +// prop value enum +func (m *HTTPResponseRule) validateTimeoutTypeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, httpResponseRuleTypeTimeoutTypePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *HTTPResponseRule) validateTimeoutType(formats strfmt.Registry) error { + if swag.IsZero(m.TimeoutType) { // not required + return nil + } + + // value enum + if err := m.validateTimeoutTypeEnum("timeout_type", "body", m.TimeoutType); err != nil { + return err + } + + return nil +} + func (m *HTTPResponseRule) validateTosValue(formats strfmt.Registry) error { if swag.IsZero(m.TosValue) { // not required return nil @@ -1048,7 +1104,7 @@ var httpResponseRuleTypeTypePropEnum []interface{} func init() { var res []string - if err := json.Unmarshal([]byte(`["add-acl","add-header","allow","cache-store","capture","del-acl","del-header","del-map","deny","lua","redirect","replace-header","replace-value","return","sc-add-gpc","sc-inc-gpc","sc-inc-gpc0","sc-inc-gpc1","sc-set-gpt0","send-spoe-group","set-header","set-log-level","set-map","set-mark","set-nice","set-status","set-tos","set-var","set-var-fmt","silent-drop","strict-mode","track-sc0","track-sc1","track-sc2","track-sc","unset-var","wait-for-body","set-bandwidth-limit"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["add-acl","add-header","allow","cache-store","capture","del-acl","del-header","del-map","deny","lua","redirect","replace-header","replace-value","return","sc-add-gpc","sc-inc-gpc","sc-inc-gpc0","sc-inc-gpc1","sc-set-gpt0","send-spoe-group","set-header","set-log-level","set-map","set-mark","set-nice","set-status","set-timeout","set-tos","set-var","set-var-fmt","silent-drop","strict-mode","track-sc0","track-sc1","track-sc2","track-sc","unset-var","wait-for-body","set-bandwidth-limit"]`), &res); err != nil { panic(err) } for _, v := range res { @@ -1136,6 +1192,9 @@ const ( // HTTPResponseRuleTypeSetDashStatus captures enum value "set-status" HTTPResponseRuleTypeSetDashStatus string = "set-status" + // HTTPResponseRuleTypeSetDashTimeout captures enum value "set-timeout" + HTTPResponseRuleTypeSetDashTimeout string = "set-timeout" + // HTTPResponseRuleTypeSetDashTos captures enum value "set-tos" HTTPResponseRuleTypeSetDashTos string = "set-tos" diff --git a/models/http_response_rule_compare.go b/models/http_response_rule_compare.go index f6c2ebab..04d72d3d 100644 --- a/models/http_response_rule_compare.go +++ b/models/http_response_rule_compare.go @@ -210,6 +210,14 @@ func (s HTTPResponseRule) Equal(t HTTPResponseRule, opts ...Options) bool { return false } + if s.Timeout != t.Timeout { + return false + } + + if s.TimeoutType != t.TimeoutType { + return false + } + if s.TosValue != t.TosValue { return false } @@ -478,6 +486,14 @@ func (s HTTPResponseRule) Diff(t HTTPResponseRule, opts ...Options) map[string][ diff["StrictMode"] = []interface{}{s.StrictMode, t.StrictMode} } + if s.Timeout != t.Timeout { + diff["Timeout"] = []interface{}{s.Timeout, t.Timeout} + } + + if s.TimeoutType != t.TimeoutType { + diff["TimeoutType"] = []interface{}{s.TimeoutType, t.TimeoutType} + } + if s.TosValue != t.TosValue { diff["TosValue"] = []interface{}{s.TosValue, t.TosValue} } diff --git a/models/http_response_rule_compare_test.go b/models/http_response_rule_compare_test.go index 62a26f93..2421dc67 100644 --- a/models/http_response_rule_compare_test.go +++ b/models/http_response_rule_compare_test.go @@ -195,7 +195,7 @@ func TestHTTPResponseRuleDiffFalse(t *testing.T) { for _, sample := range samples { result := sample.a.Diff(sample.b) - if len(result) != 59-1 { + if len(result) != 61-1 { json := jsoniter.ConfigCompatibleWithStandardLibrary a, err := json.Marshal(&sample.a) if err != nil { @@ -205,7 +205,7 @@ func TestHTTPResponseRuleDiffFalse(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - t.Errorf("Expected HTTPResponseRule to be different in 59 cases, but it is not (%d) %s %s", len(result), a, b) + t.Errorf("Expected HTTPResponseRule to be different in 61 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 3ea64836..7bb2837f 100644 --- a/specification/build/haproxy_spec.yaml +++ b/specification/build/haproxy_spec.yaml @@ -4185,6 +4185,7 @@ definitions: enum: - server - tunnel + - client type: string x-dependency: type: @@ -4791,6 +4792,22 @@ definitions: type: required: true value: strict-mode + timeout: + type: string + x-dependency: + type: + required: true + value: set-timeout + timeout_type: + enum: + - server + - tunnel + - client + type: string + x-dependency: + type: + required: true + value: set-timeout tos_value: pattern: ^(0x[0-9A-Fa-f]+|[0-9]+)$ type: string @@ -4900,6 +4917,7 @@ definitions: - set-mark - set-nice - set-status + - set-timeout - set-tos - set-var - set-var-fmt diff --git a/specification/models/configuration/http/request.yaml b/specification/models/configuration/http/request.yaml index 2e9e3c2d..dd7c7fc3 100644 --- a/specification/models/configuration/http/request.yaml +++ b/specification/models/configuration/http/request.yaml @@ -237,7 +237,7 @@ http_request_rule: value: path-strip-dotdot timeout_type: type: string - enum: [server, tunnel] + enum: [server, tunnel, client] x-dependency: type: value: set-timeout diff --git a/specification/models/configuration/http/response.yaml b/specification/models/configuration/http/response.yaml index 0324d6ce..dd43da85 100644 --- a/specification/models/configuration/http/response.yaml +++ b/specification/models/configuration/http/response.yaml @@ -39,6 +39,7 @@ http_response_rule: - set-mark - set-nice - set-status + - set-timeout - set-tos - set-var - set-var-fmt @@ -99,6 +100,19 @@ http_response_rule: type: value: redirect required: true + timeout_type: + type: string + enum: [server, tunnel, client] + x-dependency: + type: + value: set-timeout + required: true + timeout: + type: string + x-dependency: + type: + value: set-timeout + required: true hdr_name: type: string x-display-name: Header Name