-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OCPBUGS-6958: Fix clipHAProxyTimeoutValue #483
OCPBUGS-6958: Fix clipHAProxyTimeoutValue #483
Conversation
@candita: This pull request references Jira Issue OCPBUGS-6958, which is invalid:
Comment The bug has been updated to refer to the pull request using the external bug tracker. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
4a7018e
to
b21bc15
Compare
/jira refresh |
@candita: This pull request references Jira Issue OCPBUGS-6958, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
pkg/router/template/util/util.go
Outdated
// Consume [-+]? | ||
if s != "" { | ||
c := s[0] | ||
if c == '-' || c == '+' { | ||
neg = c == '-' | ||
s = s[1:] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does HAProxy allow a leading +/-? Doesn't look like it does: https://git.haproxy.org/?p=haproxy-2.2.git;a=blob;f=src/tools.c#l2066
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, if people used a +/- in the past, and it had no noticeable effect, would it be ok for me to make these changes now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll just go ahead and disallow it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further thought, it makes sense to disallow it irrespective of what HAProxy allows as $timeSpecPattern
already disallows it. There's no need to have logic to parse something that would be rejected by the regexp anyway.
pkg/router/template/util/util.go
Outdated
// Consume (\.[0-9]*)? | ||
post := false | ||
if s != "" && s[0] == '.' { | ||
s = s[1:] | ||
pl := len(s) | ||
f, scale, s = leadingFraction(s) | ||
post = pl != len(s) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does HAProxy allow a decimal point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
durationToHAProxyTimespec should remove the decimal points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, but that's not for annotations, which is what this bug deals with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it does not allow a decimal point, removed the code supporting this and updated unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code to support decimal points is still present:
router/pkg/router/template/util/util.go
Lines 164 to 165 in a4b3f60
v, f uint64 // integers before, after decimal point | |
scale float64 = 1 // value = v + f/scale |
router/pkg/router/template/util/util.go
Line 175 in a4b3f60
pl := len(s) |
router/pkg/router/template/util/util.go
Lines 181 to 194 in a4b3f60
pre := pl != len(s) // whether we consumed anything before a period | |
// Consume (\.[0-9]*)? | |
post := false | |
if s != "" && s[0] == '.' { | |
s = s[1:] | |
pl := len(s) | |
f, scale, s = leadingFraction(s) | |
post = pl != len(s) | |
} | |
if !pre && !post { | |
// no digits (e.g. ".s" or "-.s") | |
return 0, InvalidInputError{errors.New("invalid duration, not a number " + orig)} | |
} |
router/pkg/router/template/util/util.go
Lines 200 to 202 in a4b3f60
if c == '.' || '0' <= c && c <= '9' { | |
break | |
} |
router/pkg/router/template/util/util.go
Lines 219 to 227 in a4b3f60
if f > 0 { | |
// float64 is needed to be nanosecond accurate for fractions of hours. | |
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) | |
v += uint64(float64(f) * (float64(unit) / scale)) | |
if v > 1<<63 { | |
// overflow | |
return HaproxyMaxTimeoutDuration, OverflowError{errors.New("invalid duration, overflow " + orig)} | |
} | |
} |
As I mentioned in other comments, the regexp disallows decimal points anyway, so there's no need to have logic to parse them.
pkg/router/template/util/util.go
Outdated
return 0, errors.New("time: invalid duration, overflow " + orig) | ||
} | ||
v *= unit | ||
if f > 0 { | ||
// float64 is needed to be nanosecond accurate for fractions of hours. | ||
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) | ||
v += uint64(float64(f) * (float64(unit) / scale)) | ||
if v > 1<<63 { | ||
// overflow | ||
return 0, errors.New("time: invalid duration, overflow " + orig) | ||
} | ||
} | ||
d += v | ||
if d > 1<<63 { | ||
return 0, errors.New("time: invalid duration, overflow " + orig) | ||
} | ||
} | ||
if neg { | ||
return -time.Duration(d), nil | ||
} | ||
if d > 1<<63-1 { | ||
return 0, errors.New("time: invalid duration, overflow " + orig) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not simply to return haproxyMaxTimeout
in case of overflow?
If you prefer to return an error value here and handle overflow in clipHAProxyTimeoutValue
, consider using a typed error value, something like this:
// OverflowError represents an overflow error from ParseDurationWithErrors.
type OverflowError struct {
error
}
func ParseDurationWithErrors(s string) (time.Duration, error) {
// ...
return 0, OverflowError{errors.New("time: invalid duration, overflow " + orig)}
// ...
}
func clipHAProxyTimeoutValue(val string) string {
// ...
duration, err := templateutil.ParseDurationWithErrors(val)
switch err.(type) {
case nil:
case templateutil.OverflowError:
return haproxyMaxTimeout
default:
return haproxyDefaultTimeout
}
// ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has its pros and cons. If a user mistakenly typed "h" instead of "s", this could really cause a problem. If they used a value that was only a small duration of time away from the max timeout, it would be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I incorporated this suggestion, thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has its pros and cons. If a user mistakenly typed "h" instead of "s", this could really cause a problem. If they used a value that was only a small duration of time away from the max timeout, it would be fine.
I meant, rather than having ParseDurationWithErrors
(which is now named ParseHAProxyDuration
with your latest changes) return an overflow error and then having clipHAProxyTimeoutValue
handle the overflow error by using the max value, why not simply have the parse function return the max value in case of overflows? If you prefer returning an overflow error and handling it in clipHAProxyTimeoutValue
, that's fine, I was just thinking you could simplify the logic a little.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intention was that it would be more easily reused if we left it up to the caller to interpret the error and choose what to do with it.
From QE side, tested it with 4.13.0-0.ci.test-2023-05-22-014550-ci-ln-qsqqkkt-latest % oc -n openshift-ingress get pods
% oc annotate route service-unsecure haproxy.router.openshift.io/timeout=100000000000s --overwrite % oc get route service-unsecure -oyaml | grep timeout % oc -n openshift-ingress rsh router-default-c9ccc9cc7-hcf2f cat haproxy.config | grep -A5 be_http:default:service-unsecure % oc -n openshift-ingress get pods % curl http://service-unsecure-default.apps.ci-ln-qsqqkkt-72292.origin-ci-int-gce.dev.rhcloud.com ` /label qe-approved |
@frobware has an implementation as well: https://github.com/frobware/haproxytime/tree/main |
80441cb
to
a4b3f60
Compare
/test e2e-agnostic |
e2e-agnostic failure: failed: (55.3s) 2023-06-09T17:20:52 "[sig-api-machinery] Aggregator Should be able to support the 1.17 Sample API Server using the current Aggregator [Conformance] [Suite:openshift/conformance/parallel/minimal] fail [test/e2e/apimachinery/aggregator.go:474]: could not find group version resource for dynamic client and wardle/flunders (discovery error: unable to retrieve the complete list of server APIs: wardle.example.com/v1alpha1: stale GroupVersion discovery: wardle.example.com/v1alpha1, discovery results: map[schema.GroupVersionResource]struct {}{schema.GroupVersionResource{Group:"", Version:"v1", Resource:"bindings"}:..... Recent changes for Kube bump: |
/test e2e-agnostic |
Seems like a cluster install issue, and it's repeated with different errors for days. /test e2e-agnostic |
pkg/router/template/util/util.go
Outdated
error | ||
} | ||
|
||
// InvalidInputError represents an error based on invalid input to ParseHAProxyDuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments are missing periods.
// InvalidInputError represents an error based on invalid input to ParseHAProxyDuration | |
// InvalidInputError represents an error based on invalid input to ParseHAProxyDuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I fixed all of them except this one, will get it in an upcoming update.
pkg/router/template/util/util.go
Outdated
// Consume (\.[0-9]*)? | ||
post := false | ||
if s != "" && s[0] == '.' { | ||
s = s[1:] | ||
pl := len(s) | ||
f, scale, s = leadingFraction(s) | ||
post = pl != len(s) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code to support decimal points is still present:
router/pkg/router/template/util/util.go
Lines 164 to 165 in a4b3f60
v, f uint64 // integers before, after decimal point | |
scale float64 = 1 // value = v + f/scale |
router/pkg/router/template/util/util.go
Line 175 in a4b3f60
pl := len(s) |
router/pkg/router/template/util/util.go
Lines 181 to 194 in a4b3f60
pre := pl != len(s) // whether we consumed anything before a period | |
// Consume (\.[0-9]*)? | |
post := false | |
if s != "" && s[0] == '.' { | |
s = s[1:] | |
pl := len(s) | |
f, scale, s = leadingFraction(s) | |
post = pl != len(s) | |
} | |
if !pre && !post { | |
// no digits (e.g. ".s" or "-.s") | |
return 0, InvalidInputError{errors.New("invalid duration, not a number " + orig)} | |
} |
router/pkg/router/template/util/util.go
Lines 200 to 202 in a4b3f60
if c == '.' || '0' <= c && c <= '9' { | |
break | |
} |
router/pkg/router/template/util/util.go
Lines 219 to 227 in a4b3f60
if f > 0 { | |
// float64 is needed to be nanosecond accurate for fractions of hours. | |
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) | |
v += uint64(float64(f) * (float64(unit) / scale)) | |
if v > 1<<63 { | |
// overflow | |
return HaproxyMaxTimeoutDuration, OverflowError{errors.New("invalid duration, overflow " + orig)} | |
} | |
} |
As I mentioned in other comments, the regexp disallows decimal points anyway, so there's no need to have logic to parse them.
pkg/router/template/util/util.go
Outdated
// Consume [-+]? | ||
if s != "" { | ||
c := s[0] | ||
if c == '-' || c == '+' { | ||
neg = c == '-' | ||
s = s[1:] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further thought, it makes sense to disallow it irrespective of what HAProxy allows as $timeSpecPattern
already disallows it. There's no need to have logic to parse something that would be rejected by the regexp anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, as a follow-up, it might make sense to replace clipHAProxyTimeoutValue (firstMatch $timeSpecPattern foo)
with clipHAProxyTimeoutValue foo
in haproxy-config.template
as an optimization.
pkg/router/template/util/util.go
Outdated
// ParseHAProxyDuration is similar to time.ParseDuration, but modified with meaningful | ||
// error messages for invalid input. | ||
// It parses a duration string and returns a suitable duration. A duration string is a | ||
// sequence of decimal numbers, each with optional fraction and a unit suffix, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does an optional fraction look like for days, hours, minutes, seconds, milliseconds?
Do we have test cases for said fractional values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does an optional fraction look like for days, hours, minutes, seconds, milliseconds?
Do we have test cases for said fractional values?
There are a couple test cases for fractional values:
router/pkg/router/template/template_helper_test.go
Lines 824 to 828 in a4b3f60
{ | |
value: "1.5s", | |
expected: "", | |
// Invalid input produces blank output | |
}, |
router/pkg/router/template/template_helper_test.go
Lines 838 to 842 in a4b3f60
{ | |
value: "2562047.99h", | |
expected: "", | |
// Invalid input produces blank output | |
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not allowed by HAProxy, as Miciah pointed out in #483 (comment) so I removed the tests and hopefully removed all the processing code for decimal points.
The PR description has "a value that cannot be properly parsed for other reasons is set to 5s instead of being silently allowed" - will we ever back port this change in behaviour? |
Seems reasonable to me if requested. Silently allowing values that cannot be parsed breaks reloads. BTW, @candita, can you make sure the information in the PR description makes it into the commit message? |
- a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests.
@candita: all tests passed! Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/lgtm |
I think it's totally reasonable that ParseDuration will parse 0 without reporting a syntax error. The semantic layering is wrong. Not accepting 0 is a property of the clip function; ParseDuration should be the generic case. Proposal:
/remove-lgtm |
/hold |
The "/lgtm cancel" turned up. /hold cancel |
@frobware the HAProxy template does not accept 0 as the leading character. I thought we all agreed to make the regex pattern the same here as it is in HAProxy in #483 (comment). Are you referring to something different? |
I previously gave this PR an Counter-Argument for Allowing
|
I understand the argument for consistency. However, I discussed this with @candita, and currently, all values that get parsed using |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Miciah The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@candita: Jira Issue OCPBUGS-6958: All pull requests linked via external trackers have merged: Jira Issue OCPBUGS-6958 has been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Fix included in accepted release 4.15.0-0.nightly-2023-10-31-054858 |
[ART PR BUILD NOTIFIER] This PR has been included in build ose-haproxy-router-base-container-v4.15.0-202311202349.p0.gfb70ac4.assembly.stream for distgit ose-haproxy-router-base. |
/cherry-pick release-4.14 |
@candita: #483 failed to apply on top of branch "release-4.14":
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
* OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * add haproxytime * use pkg/router/template/util/haproxytime * drop existing ParseHAProxyDuration * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. --------- Co-authored-by: Andrew McDermott <[email protected]>
/cherry-pick release-4.13 |
@Miciah: #483 failed to apply on top of branch "release-4.13":
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
* OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * add haproxytime * use pkg/router/template/util/haproxytime * drop existing ParseHAProxyDuration * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. --------- Co-authored-by: Andrew McDermott <[email protected]>
* OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * add haproxytime * use pkg/router/template/util/haproxytime * drop existing ParseHAProxyDuration * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: * a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout * a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseHAProxyDuration to the util package so we can evaluate the errors returned by time.ParseDuration without sacrificing its authority in parsing time strings. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. * OCPBUGS-6958: Fix clipHAProxyTimeoutValue so that: - a value larger than time.ParseDuration can handle is clipped to the HAProxy max timeout - a value that cannot be properly parsed for other reasons is set to empty instead of being silently allowed To check that time.ParseDuration is experiencing overflow, add a new ParseDuration so we can evaluate the errors that wouldn't have been explicitly returned by time.ParseDuration, e.g. invalid HAProxy time format syntax and integer overflows. Add more unit tests. --------- Co-authored-by: Andrew McDermott <[email protected]>
Fix clipHAProxyTimeoutValue so that:
To check that
time.ParseDuration
is experiencing overflow, add a newParseDuration
so we can evaluate the errors that wouldn't have been explicitly returned bytime.ParseDuration
, e.g. invalid HAProxy time format syntax and integer overflows.Add more unit tests.