-
Notifications
You must be signed in to change notification settings - Fork 79
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
Consider DC-level config when validating numToken updates in webhook (fixes #1222) #1358
Conversation
for dcName, newNumTokens := range newNumTokensPerDc { | ||
oldNumTokens, oldExists := oldNumTokensPerDc[dcName] | ||
if oldExists && oldNumTokens != newNumTokens { | ||
return ErrNumTokens |
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.
We could add more details and keep iterating to get an exhaustive list, but I'm not sure if it's worth it.
return nil | ||
} | ||
|
||
func numTokensPerDc(cassandra *CassandraClusterTemplate) (map[string]interface{}, error) { |
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.
question: Why interface{} and not map[string]float64. Or actually just map[string]uint / int, since we don't use floats for anything in reality (it's a YAML/JSON problem) and we should throw an error if we can't map to uint value.
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.
Because it's good enough for the task at hand, which is only about comparing values.
We could indeed check that the values are integers, but then why stop at num_tokens
, and not have the webhook validate every other config value? It's not the approach we have taken so far, so I assume we want to keep things as light as possible here and do more advanced checks later (in this case computeDcNumTokens()
).
As to float64 for the defaults, it's because that's what unmarshaling into Unstructured
produces for any numeric value:
u := new(Unstructured)
u.UnmarshalJSON([]byte(`{"num_token": 16}`))
numToken, _ := u.Get("num_token")
i16 := 16
f16 := float64(i16)
fmt.Println("numToken==i16", numToken == i16) // false
fmt.Println("numToken==f16", numToken == f16) // true
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.
As to float64 for the defaults, it's because that's what unmarshaling into Unstructured produces for any numeric value
It is, because JSON & YAML do not accept any other numeric value. Problem itself is more interesting if you compare:
"num_tokens": "16" and "num_tokens": 16. Both are the same value, but they could be unmarshalled differently. We do not force users to use : 16 or : "16" and most users wouldn't even able to tell what the difference is. From your example, we end up with a difference however:
func TestUnmarshalNumbers(t *testing.T) {
dest := make(map[string]interface{}, 1)
assert.NoError(t, json.Unmarshal([]byte(`{"num_token": "16"}`), &dest))
numToken := dest["num_token"]
i16 := 16
f16 := float64(i16)
assert.NotEqual(t, numToken, i16)
assert.NotEqual(t, numToken, f16)
}
Neither compare will work. One needs to parse it first as number (using strconv) and only then compare the resulting int.
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.
True, this PR assumes the user will provide a YAML number (as does the current implementation on the main branch btw).
If supporting YAML strings is also a requirement, then it would make sense to parse.
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.
suggestion: I'm going to approve since current main branch behavior is "wrong" also, but we really shouldn't expect users to have their YAML as numbers always, since we also have situations where we require user to input the number as string instead of number (to avoid string/uint64 -> float64 issue, like we had the bug with weird commit number begin parsed as a number).
74bfa69
to
53231f2
Compare
What this PR does:
Instead of only comparing the top-level config (which can fail if fields are missing), compute and compare the numToken of each individual DC, using the inheritance and defaulting rules.
This also covers cases that were not handled before, like config being nil on one side but not the other.
Which issue(s) this PR fixes:
Fixes #1222
Checklist