-
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
Changes from 32 commits
adf92b3
65d98ec
0ff79ad
96879d5
c43e823
2c690bc
5f81aed
56ea391
7dca0d4
df5724d
b7814e7
7511fa3
fbd7d10
2f29519
766c31b
754635d
7d6a6a3
c9c6826
6348299
d398cf3
7be1995
0c4d152
c5df20c
a2fa915
86305d2
c573373
3b1ed31
d61031c
136a6c0
f7b12e0
1eae0a2
24c1533
bbfef12
a554cda
801ecf6
5a3f913
6a69ce8
f0d1e86
8bfe4a1
4d4bea3
901a0e1
b88741b
a2715ed
ae518fb
ec040a6
ae0a3c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -54,6 +54,7 @@ const ( | |||||||||||||||||||||||||||||||||||||||||||||
S3Prefix = "s3://" | ||||||||||||||||||||||||||||||||||||||||||||||
GCloudPrefix = "gs://" | ||||||||||||||||||||||||||||||||||||||||||||||
AzurePrefix = "azb://" | ||||||||||||||||||||||||||||||||||||||||||||||
trueString = "true" | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// hdfsPrefixes are prefixes for an HDFS path. | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -105,7 +106,7 @@ func (v *VerticaDB) ValidateCreate() error { | |||||||||||||||||||||||||||||||||||||||||||||
verticadblog.Info("validate create", "name", v.Name, "GroupVersion", GroupVersion) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
allErrs := v.validateVerticaDBSpec() | ||||||||||||||||||||||||||||||||||||||||||||||
if allErrs == nil { | ||||||||||||||||||||||||||||||||||||||||||||||
if len(allErrs) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaDBKind}, v.Name, allErrs) | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -116,7 +117,8 @@ func (v *VerticaDB) ValidateUpdate(old runtime.Object) error { | |||||||||||||||||||||||||||||||||||||||||||||
verticadblog.Info("validate update", "name", v.Name, "GroupVersion", GroupVersion) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
allErrs := append(v.validateImmutableFields(old), v.validateVerticaDBSpec()...) | ||||||||||||||||||||||||||||||||||||||||||||||
if allErrs == nil { | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
if len(allErrs) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaDBKind}, v.Name, allErrs) | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -148,6 +150,11 @@ func (v *VerticaDB) validateImmutableFields(old runtime.Object) field.ErrorList | |||||||||||||||||||||||||||||||||||||||||||||
allErrs = v.checkImmutableStsName(oldObj, allErrs) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = v.checkValidSubclusterTypeTransition(oldObj, allErrs) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = v.checkSandboxesDuringUpgrade(oldObj, allErrs) | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the same function structure and call these |
||||||||||||||||||||||||||||||||||||||||||||||
return allErrs | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1591,6 +1598,23 @@ func (v *VerticaDB) findPersistScsInSandbox(oldObj *VerticaDB) map[string]int { | |||||||||||||||||||||||||||||||||||||||||||||
return persistScsWithSbIndex | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// findPersistSandboxes returns a slice of sandbox names that are in both new and old vdb. | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be addressed. |
||||||||||||||||||||||||||||||||||||||||||||||
for _, oldSandbox := range oldSandboxes { | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandboxMap[oldSandbox.Name] = 1 | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
persistSandboxes := make([]string, 0) | ||||||||||||||||||||||||||||||||||||||||||||||
for _, newSandbox := range newSandboxes { | ||||||||||||||||||||||||||||||||||||||||||||||
if _, ok := oldSandboxMap[newSandbox.Name]; ok { | ||||||||||||||||||||||||||||||||||||||||||||||
persistSandboxes = append(persistSandboxes, newSandbox.Name) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return persistSandboxes | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// checkImmutableSubclusterInSandbox ensures we do not scale and remove any subcluster that is in a sandbox | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) checkImmutableSubclusterInSandbox(oldObj *VerticaDB, allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
// if either old vdb or new vdb does not have any sandboxes, skip this check | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1668,13 +1692,15 @@ func (v *VerticaDB) checkSandboxPrimary(allErrs field.ErrorList, oldObj *Vertica | |||||||||||||||||||||||||||||||||||||||||||||
oldSbMap := oldObj.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSbMap := v.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
for oldScName, oldSbName := range oldScInSandbox { | ||||||||||||||||||||||||||||||||||||||||||||||
newSbName, newFound := newScInSandbox[oldScName] | ||||||||||||||||||||||||||||||||||||||||||||||
sc := oldScMap[oldScName] | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// sandbox is removed | ||||||||||||||||||||||||||||||||||||||||||||||
if _, sandboxExist := newSbMap[oldSbName]; !sandboxExist { | ||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
newSbName, newFound := newScInSandbox[oldScName] | ||||||||||||||||||||||||||||||||||||||||||||||
// old sandbox still exits | ||||||||||||||||||||||||||||||||||||||||||||||
if !newFound && sc.Type == SandboxPrimarySubcluster { | ||||||||||||||||||||||||||||||||||||||||||||||
i := oldScIndexMap[oldScName] | ||||||||||||||||||||||||||||||||||||||||||||||
err := field.Invalid(path.Index(i), | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1683,11 +1709,12 @@ func (v *VerticaDB) checkSandboxPrimary(allErrs field.ErrorList, oldObj *Vertica | |||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// old sandbox exists and subcluster either exists (primary or nonprimary) or removed (nonprimary) | ||||||||||||||||||||||||||||||||||||||||||||||
// Remaining check is concerned with subclusters moving between sandboxes. | ||||||||||||||||||||||||||||||||||||||||||||||
if oldSbName == newSbName { | ||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
// old sandbox name does not match new sandbox name | ||||||||||||||||||||||||||||||||||||||||||||||
if sc.Type == SandboxPrimarySubcluster { | ||||||||||||||||||||||||||||||||||||||||||||||
i := oldSbIndexMap[oldSbName] | ||||||||||||||||||||||||||||||||||||||||||||||
p := field.NewPath("spec").Child("sandboxes") | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1701,6 +1728,194 @@ 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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Follow the same forma for other functions |
||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) validateNewSBoxOrSClusterShutdownUnset(allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
statusSClusterMap := v.GenStatusSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
statusSBoxMap := v.GenStatusSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
for i := range v.Spec.Sandboxes { | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
newSBox.Shutdown, | ||||||||||||||||||||||||||||||||||||||||||||||
fmt.Sprintf("shutdown must be false when adding sandbox %q", | ||||||||||||||||||||||||||||||||||||||||||||||
newSBox.Name)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
for i := range v.Spec.Subclusters { | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
newSCluster.Shutdown, | ||||||||||||||||||||||||||||||||||||||||||||||
fmt.Sprintf("shutdown must be false when adding subcluster %q", | ||||||||||||||||||||||||||||||||||||||||||||||
newSCluster.Name)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return allErrs | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// return a map whose key is the pointer of a subcluster that is to be unsandboxed. The value is the pointer to a sandbox | ||||||||||||||||||||||||||||||||||||||||||||||
// where the subcluster lives in | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) findSclustersToUnsandbox(old runtime.Object) map[*Subcluster]*Sandbox { | ||||||||||||||||||||||||||||||||||||||||||||||
oldObj := old.(*VerticaDB) | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just past this as argument? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then the casting will be done in the caller of this function. It makes no difference. |
||||||||||||||||||||||||||||||||||||||||||||||
oldSubclusterInSandbox := oldObj.GenSubclusterSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSuclusterInSandbox := v.GenSubclusterSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubclusterMap := oldObj.GenSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandboxMap := oldObj.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe 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 commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
_, oldSubclusterInPersist := newSubclusterMap[oldSubclusterName] | ||||||||||||||||||||||||||||||||||||||||||||||
// for unsandboxing, check shutdown field of the subcluster and sandbox | ||||||||||||||||||||||||||||||||||||||||||||||
if !oldSubclusterInNewSandboxes && oldSubclusterInPersist { | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubcluster := oldSubclusterMap[oldSubclusterName] | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandbox := oldSandboxMap[oldSandboxName] | ||||||||||||||||||||||||||||||||||||||||||||||
sclusterSboxMap[oldSubcluster] = oldSandbox | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return sclusterSboxMap | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// 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 { | ||||||||||||||||||||||||||||||||||||||||||||||
statusSClusterIndexMap := v.GenStatusSClusterIndexMap() | ||||||||||||||||||||||||||||||||||||||||||||||
sclustersToUnsandbox := v.findSclustersToUnsandbox(old) | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
for oldSubcluster, oldSandbox := range sclustersToUnsandbox { | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubclusterIndex := statusSClusterIndexMap[oldSubcluster.Name] | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always make sure the subcluster is in the status. If it is not(very unlikely), skip it. |
||||||||||||||||||||||||||||||||||||||||||||||
if oldSubcluster.Shutdown || v.Status.Subclusters[oldSubclusterIndex].Shutdown { | ||||||||||||||||||||||||||||||||||||||||||||||
p := field.NewPath("spec").Child("subclusters") | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
err := field.Invalid(p, | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubcluster.Name, | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
fmt.Sprintf("cannot unsandbox subcluster %q that has Shutdown field set to true", | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubcluster.Name)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
if oldSandbox.Shutdown { | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return allErrs | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// ensure: when a sandbox is to be shutdown, if a subcluster in it has annotation vertica.com/shutdown-driven-by-sandbox set to true, the | ||||||||||||||||||||||||||||||||||||||||||||||
// subcluster's shutdown field should not be updated | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) validateAnnotatedSubclustersInShutdownSandbox(old runtime.Object, allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
oldObj := old.(*VerticaDB) | ||||||||||||||||||||||||||||||||||||||||||||||
persistSandboxes := v.findPersistSandboxes(oldObj) | ||||||||||||||||||||||||||||||||||||||||||||||
newSandboxMap := v.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandboxMap := oldObj.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSubclusterIndexMap := v.GenSubclusterIndexMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSubclusterMap := v.GenSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
oldSubclusterMap := oldObj.GenSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
for _, sandboxName := range persistSandboxes { | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. This is from the JIRA: " If a sandbox has There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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) |
||||||||||||||||||||||||||||||||||||||||||||||
oldSubcluster := oldSubclusterMap[subclusterName.Name] | ||||||||||||||||||||||||||||||||||||||||||||||
if vmeta.GetShutdownDrivenBySandbox(oldSubcluster.Annotations) { | ||||||||||||||||||||||||||||||||||||||||||||||
newSubcluster, oldSclusterPersist := newSubclusterMap[subclusterName.Name] | ||||||||||||||||||||||||||||||||||||||||||||||
if oldSclusterPersist && oldSubcluster.Shutdown != newSubcluster.Shutdown { | ||||||||||||||||||||||||||||||||||||||||||||||
index := newSubclusterIndexMap[subclusterName.Name] | ||||||||||||||||||||||||||||||||||||||||||||||
p := field.NewPath("spec").Child("subclusters") | ||||||||||||||||||||||||||||||||||||||||||||||
err := field.Invalid(p.Index(index), | ||||||||||||||||||||||||||||||||||||||||||||||
subclusterName.Name, | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
subclusterName.Name)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return allErrs | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// ensures a sandbox's image is not updated after the sandbox or any of its subclusters are shut down | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) validateShutdownSandboxImage(old runtime.Object, allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment for this function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Why don't we allow shutdown in db creation?" That rule will be changed to the following per Roy's comment: I will implement this new rule. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, and this is because we want to keep things simple, the users must first create the subcluster/sandbox before they can shut it down. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should have one more rule: if the sandbox is shut down or partial shut down, we cannot add or remove any subclusters in it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The remove scenario is covered by unsandbox. We can discuss with Roy about the add scenario. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||||||||||||||||||||||||||||||||||||||||||||
oldObj := old.(*VerticaDB) | ||||||||||||||||||||||||||||||||||||||||||||||
persistSandboxes := v.findPersistSandboxes(oldObj) | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandboxMap := oldObj.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSandboxMap := v.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSandboxIndexMap := v.GenSandboxIndexMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSubclusterMap := v.GenSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
statusSClusterIndexMap := v.GenStatusSClusterIndexMap() | ||||||||||||||||||||||||||||||||||||||||||||||
for _, sandboxName := range persistSandboxes { | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandbox := oldSandboxMap[sandboxName] | ||||||||||||||||||||||||||||||||||||||||||||||
newSandbox := newSandboxMap[sandboxName] | ||||||||||||||||||||||||||||||||||||||||||||||
if oldSandbox.Image != newSandbox.Image { | ||||||||||||||||||||||||||||||||||||||||||||||
newSandboxIndex := newSandboxIndexMap[sandboxName] | ||||||||||||||||||||||||||||||||||||||||||||||
errMsg := v.checkSboxForShutdown(newSandbox, newSubclusterMap, statusSClusterIndexMap) | ||||||||||||||||||||||||||||||||||||||||||||||
if errMsg != "" { | ||||||||||||||||||||||||||||||||||||||||||||||
p := field.NewPath("spec").Child("sandboxes").Index(newSandboxIndex) | ||||||||||||||||||||||||||||||||||||||||||||||
err := field.Invalid(p.Child("image"), | ||||||||||||||||||||||||||||||||||||||||||||||
sandboxName, | ||||||||||||||||||||||||||||||||||||||||||||||
LiboYu2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
fmt.Sprintf("cannot change the image for sandbox %q because %q", | ||||||||||||||||||||||||||||||||||||||||||||||
sandboxName, errMsg)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return allErrs | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// ensure the sandbox to terminate is not shut down | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) validateTerminatingSandboxes(old runtime.Object, allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment for this function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can simplify this rule to "we cannot remove any subclusters that are shut down". Preventing removing the sandbox should already be covered in validateUnsandboxShutdownConditions. We should remove this rule in future since a stopped subcluster/sandbox should be able to removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is from the JIRA requirement: "terminate means removing the sandbox in spec.sandboxes[] and its subclusters in spec.subclusters[] at the same time." |
||||||||||||||||||||||||||||||||||||||||||||||
oldObj := old.(*VerticaDB) | ||||||||||||||||||||||||||||||||||||||||||||||
oldSandboxMap := oldObj.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
newSandboxMap := v.GenSandboxMap() | ||||||||||||||||||||||||||||||||||||||||||||||
sandboxesToBeRemoved := vutil.MapKeyDiff(oldSandboxMap, newSandboxMap) | ||||||||||||||||||||||||||||||||||||||||||||||
newSubclusterMap := v.GenSubclusterMap() | ||||||||||||||||||||||||||||||||||||||||||||||
for _, sandboxToBeRemoved := range sandboxesToBeRemoved { | ||||||||||||||||||||||||||||||||||||||||||||||
numOfSclustersInSbox := len(oldSandboxMap[sandboxToBeRemoved].Subclusters) | ||||||||||||||||||||||||||||||||||||||||||||||
sclustersToTerminate := numOfSclustersInSbox | ||||||||||||||||||||||||||||||||||||||||||||||
for _, subcluster := range oldSandboxMap[sandboxToBeRemoved].Subclusters { | ||||||||||||||||||||||||||||||||||||||||||||||
if _, ok := newSubclusterMap[subcluster.Name]; ok { | ||||||||||||||||||||||||||||||||||||||||||||||
sclustersToTerminate-- | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
// 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 commentThe 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 commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, if
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
p := field.NewPath("spec").Child("sandboxes") | ||||||||||||||||||||||||||||||||||||||||||||||
err := field.Invalid(p, | ||||||||||||||||||||||||||||||||||||||||||||||
sandboxToBeRemoved, | ||||||||||||||||||||||||||||||||||||||||||||||
fmt.Sprintf("cannot terminate sandbox %q that has Shutdown field set to true", | ||||||||||||||||||||||||||||||||||||||||||||||
sandboxToBeRemoved)) | ||||||||||||||||||||||||||||||||||||||||||||||
allErrs = append(allErrs, err) | ||||||||||||||||||||||||||||||||||||||||||||||
} // else looks good | ||||||||||||||||||||||||||||||||||||||||||||||
} // else is expected | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Enrich the comment to explain the returned value. |
||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
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 commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
for _, subcluster := range newSandbox.Subclusters { | ||||||||||||||||||||||||||||||||||||||||||||||
i, foundInStatus := statusSClusterIndexMap[subcluster.Name] | ||||||||||||||||||||||||||||||||||||||||||||||
if foundInStatus && (newSClusterMap[subcluster.Name].Shutdown || v.Status.Subclusters[i].Shutdown) { | ||||||||||||||||||||||||||||||||||||||||||||||
LiboYu2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as the above one. |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return "" | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// checkImmutableStsName ensures the statefulset name of the subcluster stays constant | ||||||||||||||||||||||||||||||||||||||||||||||
func (v *VerticaDB) checkImmutableStsName(oldObj *VerticaDB, allErrs field.ErrorList) field.ErrorList { | ||||||||||||||||||||||||||||||||||||||||||||||
// We have an annotation to control the sts name. We are not going to allow | ||||||||||||||||||||||||||||||||||||||||||||||
|
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