-
Notifications
You must be signed in to change notification settings - Fork 25
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
webhook rules for sandbox shutdown #971
Conversation
api/v1/verticadb_webhook.go
Outdated
func (v *VerticaDB) checkSboxForShutdownInSpecAndStatus(sandbox *Sandbox, subclusterMap map[string]*Subcluster, subclusterIndexMap map[string]int, errMsgs []string) []string { | ||
errMsgs = v.checkSboxForShutdownInSpec(sandbox, subclusterMap, errMsgs) | ||
for _, subcluster := range sandbox.Subclusters { | ||
if v.Status.Subclusters[subclusterIndexMap[subcluster.Name]].Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown status of subcluster %q is true", subcluster.Name)) | ||
} | ||
} | ||
return errMsgs | ||
} | ||
|
||
func (v *VerticaDB) checkSboxForShutdownInSpec(sandbox *Sandbox, subclusterMap map[string]*Subcluster, errMsgs []string) []string { | ||
if sandbox.Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown field of sandbox %q is set to true", sandbox.Name)) | ||
} | ||
for _, subcluster := range sandbox.Subclusters { | ||
if subclusterMap[subcluster.Name].Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown field of subcluster %q is set to true", subcluster.Name)) | ||
} | ||
} | ||
return errMsgs | ||
} |
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.
This will create too many msgs. Let's have a single loop over sandbox.Subclusters
and for each subcluster find the shutdown value in both spec and status(make sure the subcluster exists in status). If any of them is true return a generate a generic msg like subcluster %q is marked for shut down or has already been shut down
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.
"make sure the subcluster exists in status"
I got your point. When a user tries to change the sandbox image, the subcluster is already shutdown at this time. This is different from my original understanding. I will make a change.
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.
This is from the JIRA:
"You cannot change spec.sandboxes[].image if the sandbox has shutdown
true or has any subcluster with shutdown
true(spec and/or status)"
Could you remove the "or" from within the brackets? 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.
Why? I mean what I said. If you prefer here is what I mean You cannot change spec.sandboxes[].image if the sandbox has shutdown true or has any subcluster with shutdown true(spec or status)
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.
Got it. It is different from your original comment: "for each subcluster find the shutdown value in both spec and status(make sure the subcluster exists in status)."
api/v1/verticadb_webhook.go
Outdated
@@ -1701,6 +1760,162 @@ func (v *VerticaDB) checkSandboxPrimary(allErrs field.ErrorList, oldObj *Vertica | |||
return allErrs | |||
} | |||
|
|||
// validateUnsandboxShutdownConditions ensures we will not unsandbox a subcluster that has shutdown set to true, or a subcluster | |||
// in a sandbox where the shutdown field for the sandbox is set to true | |||
func (v *VerticaDB) validateUnsandboxShutdownConditions(old runtime.Object, allErrs field.ErrorList) field.ErrorList { |
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.
Split the content of this function into smaller functions to make it more readable. Unsandboxing means 2 things: 1. we removed one or multiple subclusters from sandbox or we remove one or multiple sandboxes from spec.sandboxes.
In both cases we need to identify subclusters to be unsandboxed and for each for them, check if the subcluster shutdown(spec/status) is true or if it is/was part of a sandbox that has shutdown 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.
"check if the subcluster shutdown(spec/status)"
for the condition shutdown(spec/status), is it an OR or AND? Currently I implemented it as an OR.
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 is an OR.
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 need to add one more limitation: we cannot add one or multiple subclusters to a sandbox if the sandbox is shutdown or partially shutdown. I didn't test it, but I think we cannot restart a sandboxed subcluster if that sandbox changed its group members.
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 proposed new rule can be found in another webhook JIRA VER-97254
api/v1/verticadb_webhook.go
Outdated
allErrs = v.hasNoShutdownSubclusters(allErrs) | ||
allErrs = v.hasNoShutdownSandboxes(allErrs) |
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.
Let's change the 1st rule to this: when a subcluster or sandbox is added to the vdb for the 1st time (not in status yet) they all must have shutdown field set to false.
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 believe the original 1st rule is still a valid one. The two cover different scenarios. Should we add what you proposed as a new rule?
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.
Why don't we allow shutdown in db creation?
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.
No, this new rule covers the original first rule. When you create a vdb, the subclusters and/or sandboxes in the spec will not be in the status.
api/v1/verticadb_webhook.go
Outdated
if newSandbox.Shutdown { | ||
for _, subclusterName := range oldSandbox.Subclusters { | ||
oldSubcluster := oldSubclusterMap[subclusterName.Name] | ||
if drivenby, ok := oldSubcluster.Annotations["vertica.com/shutdown-driven-by-sandbox"]; ok && drivenby == trueString { |
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.
There is already a constant in annotations.go. A function to get the annotation's value too.
Ω(newVdb.validateAnnotatedSubclustersInShutdownSandbox(oldVdb, field.ErrorList{})).Should(HaveLen(1)) | ||
newVdb.Spec.Subclusters[1].Shutdown = true | ||
Ω(newVdb.validateAnnotatedSubclustersInShutdownSandbox(oldVdb, field.ErrorList{})).Should(HaveLen(0)) | ||
|
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.
api/v1/verticadb_webhook_test.go
Outdated
newVdb.Spec.Subclusters[1].Shutdown = false | ||
Ω(newVdb.validateAnnotatedSubclustersInShutdownSandbox(oldVdb, field.ErrorList{})).Should(HaveLen(1)) | ||
newVdb.Spec.Subclusters[1].Shutdown = true | ||
Ω(newVdb.validateAnnotatedSubclustersInShutdownSandbox(oldVdb, field.ErrorList{})).Should(HaveLen(0)) |
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.
You also need the following cases:
- change sc1 shutdown and check there is no error as it is not part of the sandbox
- set sandbox.shutdown to false, rerun the above cases and check there is no 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.
new cases added
api/v1/verticadb_webhook.go
Outdated
@@ -1701,6 +1760,162 @@ func (v *VerticaDB) checkSandboxPrimary(allErrs field.ErrorList, oldObj *Vertica | |||
return allErrs | |||
} | |||
|
|||
// validateUnsandboxShutdownConditions ensures we will not unsandbox a subcluster that has shutdown set to true, or a subcluster | |||
// in a sandbox where the shutdown field for the sandbox is set to true | |||
func (v *VerticaDB) validateUnsandboxShutdownConditions(old runtime.Object, allErrs field.ErrorList) field.ErrorList { |
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 is an OR.
api/v1/verticadb_webhook.go
Outdated
func (v *VerticaDB) checkSboxForShutdownInSpecAndStatus(sandbox *Sandbox, subclusterMap map[string]*Subcluster, subclusterIndexMap map[string]int, errMsgs []string) []string { | ||
errMsgs = v.checkSboxForShutdownInSpec(sandbox, subclusterMap, errMsgs) | ||
for _, subcluster := range sandbox.Subclusters { | ||
if v.Status.Subclusters[subclusterIndexMap[subcluster.Name]].Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown status of subcluster %q is true", subcluster.Name)) | ||
} | ||
} | ||
return errMsgs | ||
} | ||
|
||
func (v *VerticaDB) checkSboxForShutdownInSpec(sandbox *Sandbox, subclusterMap map[string]*Subcluster, errMsgs []string) []string { | ||
if sandbox.Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown field of sandbox %q is set to true", sandbox.Name)) | ||
} | ||
for _, subcluster := range sandbox.Subclusters { | ||
if subclusterMap[subcluster.Name].Shutdown { | ||
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown field of subcluster %q is set to true", subcluster.Name)) | ||
} | ||
} | ||
return errMsgs | ||
} |
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.
Why? I mean what I said. If you prefer here is what I mean You cannot change spec.sandboxes[].image if the sandbox has shutdown true or has any subcluster with shutdown true(spec or status)
api/v1/verticadb_webhook.go
Outdated
allErrs = v.hasNoShutdownSubclusters(allErrs) | ||
allErrs = v.hasNoShutdownSandboxes(allErrs) |
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.
No, this new rule covers the original first rule. When you create a vdb, the subclusters and/or sandboxes in the spec will not be in the status.
Co-authored-by: Roy Paulin <[email protected]>
Co-authored-by: Roy Paulin <[email protected]>
Co-authored-by: Roy Paulin <[email protected]>
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 are getting close.
api/v1/verticadb_webhook.go
Outdated
// checkSboxForShutdown checks if sbox or its scluster has shutdown field set to true in spec/status | ||
func (v *VerticaDB) checkSboxForShutdown(newSandbox *Sandbox, newSClusterMap map[string]*Subcluster, statusSClusterIndexMap map[string]int) string { | ||
if newSandbox.Shutdown { | ||
return fmt.Sprintf("Shutdown field of sandbox %q is set to true", newSandbox.Name) |
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.
return fmt.Sprintf("Shutdown field of sandbox %q is set to true", newSandbox.Name) | |
errMsgs = append(errMsgs, fmt.Sprintf("Shutdown field of sandbox %q is set to true", newSandbox.Name)) |
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.
will make the change.
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.
Yes, but it can happen that the sandbox has shutdown true and also all its subclusters have shutdown true. In that case we want to report all the error msgs so the user is aware.
api/v1/verticadb_webhook.go
Outdated
for _, subcluster := range newSandbox.Subclusters { | ||
i, foundInStatus := statusSClusterIndexMap[subcluster.Name] | ||
if foundInStatus && (newSClusterMap[subcluster.Name].Shutdown || v.Status.Subclusters[i].Shutdown) { | ||
return fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name) |
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.
return fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name) | |
errMsgs = append(errMsgs, fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name)) |
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.
same comment as the above one.
api/v1/verticadb_webhook.go
Outdated
return fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name) | ||
} | ||
} | ||
return "" |
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.
return "" | |
return errMsgs |
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.
same comment as the above one. When it returns empty string, it means no error.
api/v1/verticadb_webhook.go
Outdated
} | ||
|
||
// checkSboxForShutdown checks if sbox or its scluster has shutdown field set to true in spec/status | ||
func (v *VerticaDB) checkSboxForShutdown(newSandbox *Sandbox, newSClusterMap map[string]*Subcluster, statusSClusterIndexMap map[string]int) string { |
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.
func (v *VerticaDB) checkSboxForShutdown(newSandbox *Sandbox, newSClusterMap map[string]*Subcluster, statusSClusterIndexMap map[string]int) string { | |
func (v *VerticaDB) checkSboxForShutdown(newSandbox *Sandbox, newSClusterMap map[string]*Subcluster, statusSClusterIndexMap map[string]int) []string { | |
errMsgs := []string{} |
We still want to return all the error msgs. We just did not want to return one batch for spec and another for status.
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.
Now I know what you want to achieve. I withdraw my previous comments and will make the change.
api/v1/verticadb_webhook.go
Outdated
allErrs = append(allErrs, err) | ||
continue | ||
} | ||
if oldSandbox.Shutdown { | ||
p := field.NewPath("spec").Child("sandboxes") | ||
err := field.Invalid(p, | ||
oldSubcluster.Name, | ||
fmt.Sprintf("cannot unsandbox subcluster %q in sandbox %q that has Shutdown field set to true", | ||
oldSubcluster.Name, oldSandbox.Name)) | ||
allErrs = append(allErrs, err) | ||
continue | ||
} |
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.
allErrs = append(allErrs, err) | |
continue | |
} | |
if oldSandbox.Shutdown { | |
p := field.NewPath("spec").Child("sandboxes") | |
err := field.Invalid(p, | |
oldSubcluster.Name, | |
fmt.Sprintf("cannot unsandbox subcluster %q in sandbox %q that has Shutdown field set to true", | |
oldSubcluster.Name, oldSandbox.Name)) | |
allErrs = append(allErrs, err) | |
continue | |
} | |
allErrs = append(allErrs, err) | |
} | |
if oldSandbox.Shutdown { | |
p := field.NewPath("spec").Child("sandboxes").Index(...) | |
err := field.Invalid(p.Child("shutdown"), | |
oldSandbox.Name, | |
fmt.Sprintf("cannot unsandbox subcluster %q in sandbox %q that has shutdown field set to true", | |
oldSubcluster.Name, oldSandbox.Name)) | |
allErrs = append(allErrs, err) | |
} |
api/v1/verticadb_webhook.go
Outdated
err := field.Invalid(p.Index(index), | ||
subclusterName.Name, |
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.
err := field.Invalid(p.Index(index), | |
subclusterName.Name, | |
err := field.Invalid(p.Index(index).Child("shutdown"), | |
newSubcluster.Shutdown, |
api/v1/verticadb_webhook.go
Outdated
p := field.NewPath("spec").Child("subclusters") | ||
err := field.Invalid(p.Index(index), | ||
subclusterName.Name, | ||
fmt.Sprintf("cannot change Shutdown field for subcluster %q that has annotation \"vertica.com/shutdown-driven-by-sandbox\" set to 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.
fmt.Sprintf("cannot change Shutdown field for subcluster %q that has annotation \"vertica.com/shutdown-driven-by-sandbox\" set to true", | |
fmt.Sprintf("cannot change shutdown field for subcluster %q whose shutdown is driven by sandbox %q", |
newSBox := v.Spec.Sandboxes[i] | ||
if _, foundInStatus := statusSBoxMap[newSBox.Name]; !foundInStatus && newSBox.Shutdown { | ||
p := field.NewPath("spec").Child("sandboxes").Index(i) | ||
err := field.Invalid(p, |
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.
err := field.Invalid(p, | |
err := field.Invalid(p.Child("shutdown"), |
newSCluster := &v.Spec.Subclusters[i] | ||
if _, foundInStatus := statusSClusterMap[newSCluster.Name]; !foundInStatus && newSCluster.Shutdown { | ||
p := field.NewPath("spec").Child("subclusters").Index(i) | ||
err := field.Invalid(p, |
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.
err := field.Invalid(p, | |
err := field.Invalid(p.child("shutdown"), |
Co-authored-by: Roy Paulin <[email protected]>
Co-authored-by: Roy Paulin <[email protected]>
…kubernetes into VER-97368-webhook-rules
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.
This is the last round. After my comments are addressed, I will approve
api/v1/verticadb_webhook.go
Outdated
if newSandbox.Shutdown { | ||
return fmt.Sprintf("Shutdown field of sandbox %q is set to true", newSandbox.Name) | ||
return append(errMsgs, fmt.Sprintf("Shutdown field of sandbox %q is set to true", newSandbox.Name)) |
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.
Do not return.
api/v1/verticadb_webhook.go
Outdated
} | ||
|
||
for _, subcluster := range newSandbox.Subclusters { | ||
i, foundInStatus := statusSClusterIndexMap[subcluster.Name] | ||
if foundInStatus && (newSClusterMap[subcluster.Name].Shutdown || v.Status.Subclusters[i].Shutdown) { | ||
return fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name) | ||
return append(errMsgs, fmt.Sprintf("Subcluster %q is marked for shut down or has already been shut down", subcluster.Name)) |
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.
Do not return.
Also to make the error msg shorter, we can first append the subcluster names and then add the msg. The err msg will look like: ......Subclusters sc1, sc2, sc3 are marked for shut down or have already been shut down.
api/v1/verticadb_webhook.go
Outdated
} | ||
// sandboxToBeRemoved and all its subclusters are not found in new spec | ||
if sclustersToTerminate == numOfSclustersInSbox { | ||
if oldSandboxMap[sandboxToBeRemoved].Shutdown { |
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.
This check should be at the beginning of the loop so you can skip to the next sandbox if the current sandbox has shutdown 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.
This if statement compares the number of subclusters to be removed with the number of subclusters in the sandbox.
If they equal, that means the sandbox will be terminated.
There is another for loop on the top of this if statement. It is used to calculate "sclustersToTerminate" used in the if statement.
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.
Again, if oldSandboxMap[sandboxToBeRemoved].Shutdown
is false then there is no point in running all this code. Check oldSandboxMap[sandboxToBeRemoved].Shutdown
at the beginning of the loop and if false skip and go to next sandbox. Something like:
for _, sandboxToBeRemoved := range sandboxesToBeRemoved {
if !oldSandboxMap[sandboxToBeRemoved].Shutdown {
continue
}
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.
That is a good point. I will check oldSandboxMap[sandboxToBeRemoved].Shutdown earlier. If it is false, let it skip the rest of the current loop.
api/v1/verticadb_webhook.go
Outdated
allErrs = v.validateShutdownSandboxImage(old, allErrs) | ||
allErrs = v.validateTerminatingSandboxes(old, allErrs) | ||
allErrs = v.validateUnsandboxShutdownConditions(old, allErrs) | ||
allErrs = v.validateAnnotatedSubclustersInShutdownSandbox(old, allErrs) | ||
allErrs = v.validateNewSBoxOrSClusterShutdownUnset(allErrs) |
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.
Let's keep the same function structure and call these check...
like checkShutdownSandboxImage
api/v1/verticadb_webhook.go
Outdated
@@ -1701,6 +1728,199 @@ func (v *VerticaDB) checkSandboxPrimary(allErrs field.ErrorList, oldObj *Vertica | |||
return allErrs | |||
} | |||
|
|||
// ensures a new subcluster or sandbox to be added to a vdb has Shutdown field set to false |
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.
// ensures a new subcluster or sandbox to be added to a vdb has Shutdown field set to false | |
// validateNewSBoxOrSClusterShutdownUnset ensures a new subcluster or sandbox to be added to a vdb has Shutdown field set to false |
Follow the same forma for other functions
api/v1/helpers.go
Outdated
return statusSboxMap | ||
} | ||
|
||
// GenStatusSandboxMap() returns a map from status. The key is subcluster name and value is the subcluster pointer |
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.
Minor: update GenStatusSandboxMap to GenStatusSubclusterMap
api/v1/verticadb_webhook.go
Outdated
func (v *VerticaDB) findPersistSandboxes(oldObj *VerticaDB) []string { | ||
oldSandboxes := oldObj.Spec.Sandboxes | ||
newSandboxes := v.Spec.Sandboxes | ||
oldSandboxMap := make(map[string]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.
Minor: this map should be a map[string]any or map[string]bool.
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.
This needs to be addressed.
api/v1/verticadb_webhook.go
Outdated
return allErrs | ||
} | ||
|
||
// findSclustersToUnsandboxreturn a map whose key is the pointer of a subcluster that is to be unsandboxed. |
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.
add space in front of "return"
api/v1/verticadb_webhook.go
Outdated
newSubclusterMap := v.GenSubclusterMap() | ||
sclusterSboxMap := make(map[*Subcluster]*Sandbox) | ||
for oldSubclusterName, oldSandboxName := range oldSubclusterInSandbox { | ||
_, oldSubclusterInNewSandboxes := newSuclusterInSandbox[oldSubclusterName] |
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.
You need to check if the old sandbox name and new sandbox name are the same. If we move a subcluster from a sandbox to another in new vdb, that subcluster is still in new vdb, but it will be unsandboxed.
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 will make code change to cover that scenario and set up a new test case.
api/v1/verticadb_webhook.go
Outdated
sandboxIndexMap := v.GenSandboxIndexMap() | ||
for oldSubcluster, oldSandbox := range subclustersToUnsandbox { | ||
oldSubclusterIndex, found := statusSClusterIndexMap[oldSubcluster.Name] | ||
if oldSubcluster.Shutdown || found && v.Status.Subclusters[oldSubclusterIndex].Shutdown { |
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.
Add parenthesis for readability.
allErrs = append(allErrs, err) | ||
continue | ||
} | ||
if oldSandbox.Shutdown { |
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.
For one sandbox, we probably reach here multiple times so we probably return duplicate errors.
newSandbox := newSandboxMap[sandboxName] | ||
oldSandbox := oldSandboxMap[sandboxName] | ||
if newSandbox.Shutdown { | ||
for _, subclusterName := range oldSandbox.Subclusters { |
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.
Why are we checking old sandbox's subclusters? Doesn't this rule apply on the subclusters in new sandbox?
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.
This is from the JIRA: " If a sandbox has shutdown
(spec) true and any of its subclusters has the annotation "vertica.com/shutdown-driven-by-sandbox" set to true in the old vdb, we should prevent the user from updating that subcluster's shutdown field. "
Here we check the subclusters that exist in both new and old vdbs.
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.
Then in line 1836, we should check oldSandbox.Shutdown.
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.
No we should check newSandbox. Here is the scenario this covers: sandbox sand1 has a subcluster sc1. you set sand1.shutdown to true, the operator will set sc1.shutdown to true and add the annotation to sc1. So now sand.shutdown = true, sc1.shutdown. true and sc1 has "vertica.com/shutdown-driven-by-sandbox". We do not want a user to come and change sc1.shutdown because that annotation is a proof that the sandbox drives the shutdown.
This is relevant only if sand1.shutdown is still true(newvdb)
return allErrs | ||
} | ||
|
||
// checkSboxForShutdown checks if sbox or its scluster has shutdown field set to true in spec/status |
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.
Enrich the comment to explain the returned value.
api/v1/verticadb_webhook.go
Outdated
func (v *VerticaDB) findPersistSandboxes(oldObj *VerticaDB) []string { | ||
oldSandboxes := oldObj.Spec.Sandboxes | ||
newSandboxes := v.Spec.Sandboxes | ||
oldSandboxMap := make(map[string]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.
This needs to be addressed.
return sclusterSboxMap | ||
} | ||
|
||
// checkUnsandboxShutdownConditions ensures we will not unsandbox a subcluster that has shutdown set to true, or a subcluster |
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.
Fix golint error of the comments here.
api/v1/verticadb_webhook.go
Outdated
} | ||
if oldSandbox.Shutdown { | ||
i := sandboxIndexMap[oldSandbox.Name] | ||
if i != unsandboxIndex { // this is to avoid duplicate error messages |
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.
Will this fix the duplicate error messages bug? In the for loop, we have this sequence: sc1, sand1; sc2, sand2; sc3, sand1. unsandboxIndex will be 1(assume sand1's index is 1), 2, 1. We still come here twice for sand1.
You should check the sandbox outside this loop or use a map to store checked sandboxes.
api/v1/verticadb_webhook.go
Outdated
_, oldSubclusterInPersist := newSubclusterMap[oldSubclusterName] | ||
oldSandbox := oldSandboxMap[oldSandboxName] | ||
// for unsandboxing, check shutdown field of the subcluster and sandbox | ||
if oldSubclusterInPersist { |
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.
This condition doesn't help. Even the subcluster does not persist, the subcluster could be unsandboxed.
newSandbox := newSandboxMap[sandboxName] | ||
oldSandbox := oldSandboxMap[sandboxName] | ||
if newSandbox.Shutdown { | ||
for _, subclusterName := range oldSandbox.Subclusters { |
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.
Then in line 1836, we should check oldSandbox.Shutdown.
api/v1/verticadb_webhook.go
Outdated
return allErrs | ||
} | ||
|
||
// checkTerminatingSandboxes ensure the sandbox to terminate is not shut down |
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.
This comment doesn't match the function implementation. I don't think we need to check if all subclusters inside the sandbox are terminating. If a "shutdown" sandbox is removed, we should error out.
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.
That's a good point. I overthought this. @LiboYu2 when a sandbox is removed check its shutdown and if it is true, block the change. We should also do the same for remove_subcluster, a subcluster must not be removed from vdb if shutdown is true, but that will be part of his other ticket. This has already taken too long.
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 will change the code to adopt the new logic. Could you update the rule in the JIRA as well?
api/v1/verticadb_webhook.go
Outdated
allErrs = v.checkShutdownSandboxImage(old, allErrs) | ||
allErrs = v.checkTerminatingSandboxes(old, allErrs) | ||
allErrs = v.checkUnsandboxShutdownConditions(old, allErrs) | ||
allErrs = v.checkAnnotatedSubclustersInShutdownSandbox(old, allErrs) | ||
allErrs = v.checkNewSBoxOrSClusterShutdownUnset(allErrs) |
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.
Directly pass oldObj to these functions to stay consistent.
api/v1/verticadb_webhook.go
Outdated
@@ -1828,20 +1828,18 @@ func (v *VerticaDB) checkAnnotatedSubclustersInShutdownSandbox(oldObj *VerticaDB | |||
for sandboxName := range persistSandboxes { | |||
newSandbox := newSandboxMap[sandboxName] | |||
oldSandbox := oldSandboxMap[sandboxName] | |||
if newSandbox.Shutdown { | |||
if newSandbox.Shutdown { // !oldSandbox.Shutdown && |
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.
Why this comment? I do not think oldSandbox.shutdown value matters.
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.
This is useless. I will remove it.
allErrs = append(allErrs, err) | ||
} | ||
newSubcluster, oldSclusterPersist := newSubclusterMap[subclusterName.Name] | ||
if oldSclusterPersist && oldSubcluster.Shutdown != newSubcluster.Shutdown && !newSubcluster.Shutdown { |
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.
Do you need the last part of this condition? We want to prevent any change.
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.
Do you mean this one "!newSubcluster.Shutdown"? It is used to check if a user sets the shutdown to false while the sandbox is marked for shutdown. It is needed.
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 want to prevent any kind of change so "oldSubcluster.Shutdown != newSubcluster.Shutdown" is enough
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.
If we only have "oldSubcluster.Shutdown != newSubcluster.Shutdown", that will stop the operator from the setting the shutdown field to true from false.
api/v1/verticadb_webhook.go
Outdated
@@ -1833,20 +1828,18 @@ func (v *VerticaDB) checkAnnotatedSubclustersInShutdownSandbox(old runtime.Objec | |||
for sandboxName := range persistSandboxes { | |||
newSandbox := newSandboxMap[sandboxName] | |||
oldSandbox := oldSandboxMap[sandboxName] | |||
if newSandbox.Shutdown { | |||
if newSandbox.Shutdown { // !oldSandbox.Shutdown && |
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.
Remove the comment in this line.
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.
removed
api/v1/verticadb_webhook.go
Outdated
@@ -1822,8 +1818,7 @@ func (v *VerticaDB) checkUnsandboxShutdownConditions(old runtime.Object, allErrs | |||
|
|||
// checkAnnotatedSubclustersInShutdownSandbox ensures: when a sandbox is to be shutdown, if a subcluster in it has annotation |
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.
Update the comment here
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.
updated.
@@ -1833,20 +1828,18 @@ func (v *VerticaDB) checkAnnotatedSubclustersInShutdownSandbox(old runtime.Objec | |||
for sandboxName := range persistSandboxes { |
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.
Why do we need the sandbox to be persistent?
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 of this condition "oldSubcluster.Shutdown != newSubcluster.Shutdown"
The rule applies when a user tries to mess with an existing subcluster. If it is a new subcluster, it will be covered by other rules.
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.
That condition is for persistent subclusters, not for persistent sandboxes.
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.
If the sandbox is not persistent, it will be a new sandbox, For new sandboxes to be created, its shutdown field will not be true. We are only concerned about subclusters in persistent sandboxes.
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.
If we have a subcluster that isn't in a sandbox of old vdb, but we put it in the sandbox of new vdb, your code cannot cover that subcluster, right?
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.
Do we have a rule to prevent a "shutdown" subcluster to add to a sandbox in your PR?
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.
Yes. There are more rules in https://jira.verticacorp.com/jira/browse/VER-97254
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.
Correct myself. Rule 1 of https://jira.verticacorp.com/jira/browse/VER-97368 covers that scenario.
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.
If we have a subcluster that isn't in a sandbox of old vdb, but we put it in the sandbox of new vdb, your code cannot cover that subcluster, right?
Right. That is the sandboxing scenario. It will be covered in https://jira.verticacorp.com/jira/browse/VER-97254
api/v1/verticadb_webhook.go
Outdated
} | ||
// sandboxToBeRemoved and all its subclusters are not found in new spec | ||
if sclustersToTerminate == numOfSclustersInSbox { | ||
} else { |
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.
You can remove the else here since you already used a "continue" in line 1884
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.
with the "else", it is easier to read and understand the logic.
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.
Then line 1884 doesn't make sense. You can just use if oldSandboxMap[sandboxToBeRemoved].Shutdown
, what's the point to use an else block.
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 will remove it.
Here are the rules that are implemented by this change.
shutdown
set to true.shutdown
(spec) true and any of its subclusters has the annotation "vertica.com/shutdown-driven-by-sandbox" set to true in the old vdb, we should prevent the user from updating that subcluster's shutdown field.shutdown
true(spec and/or status) or part of a sandbox withshutdown
trueshutdown
true or has any subcluster withshutdown
true(spec and/or status)shutdown
true. terminate means removing the sandbox in spec.sandboxes[] and its subclusters in spec.subclusters[] at the same time.