PWX-31470: Clusterwide operator CR migration support.#1451
PWX-31470: Clusterwide operator CR migration support.#1451diptiranjanpx merged 1 commit intomasterfrom
Conversation
|
Can one of the admins verify this patch? |
pp511
left a comment
There was a problem hiding this comment.
Looks ok. Some nits and one concern related to newOwnerUIDMapping fetch.
| // Clusterwide Operators will control the CRs in all namespaces | ||
| // StashStratergy option will make sure as part of migration the CR does not get applied | ||
| // if StashCR is enabled. The CR will be applied as part of app activation | ||
| StashStratergy StashStratergy `json:"stashStratergy"` |
| // StashStratergy to restrict CR applying during migration | ||
| type StashStratergy struct { |
| log.MigrationLog(migration).Infof("getting configmap details for stashing resource %s/%s", unstructured.GetKind(), unstructured.GetName()) | ||
| unstructured, err = getStashedConfigMap(unstructured) | ||
| if err != nil { | ||
| log.MigrationLog(migration).Warnf("unable to get stashed configmap content for object %s/%s, error: %v", unstructured.GetKind(), unstructured.GetName(), err) |
There was a problem hiding this comment.
Do we want to move ahead here despite the error?
There was a problem hiding this comment.
That function returns an error only in case of json marshal which is unlikely to fail. But we should continue in the for loop and avoid going ahead in this function.
There was a problem hiding this comment.
We decided we will continue in the error case. This has not been addressed yet.
There was a problem hiding this comment.
Instead of continue , addressed with a goto such that we can update the migration CR with error message.
| return pvToPVCMapping | ||
| } | ||
|
|
||
| func getStashCREnabledAppRegs(crdList stork_api.ApplicationRegistrationList) map[string]bool { |
There was a problem hiding this comment.
nit..Since the function is named getStashCREnabledAppRegs. So maybe we can return a list of AppReg for which StashCR is true. Also we won't have to validate true or false on the caller side. Or we should rename this to avoid confusion
There was a problem hiding this comment.
Renamed it to "getAppRegsStashMap".
Returning a list of AppRegs and again checking whether for a crd if stash strategy is enabled is costly.
| configMap.SetGroupVersionKind(schema.GroupVersionKind{ | ||
| Group: "", | ||
| Version: "v1", | ||
| Kind: "ConfigMap", | ||
| }) |
There was a problem hiding this comment.
nit..I think it would be cleaner to not use unstructured cm here(as used "core v1 . ConfigMap{}) so we won't have to explicitly set gvk. We can convert it to unstructured when we are returning from the function
There was a problem hiding this comment.
+1 on this - would be easier to just create a corev1.ConfigMap objet and then convert it to unstructered.
pkg/resourceutils/updatereplicas.go
Outdated
| return | ||
| } | ||
| ruleset := resourcecollector.GetDefaultRuleSet() | ||
| // Create the CRs in the same namespace if those dont exist |
There was a problem hiding this comment.
nit..nit.. don't or do not :)
pkg/resourceutils/updatereplicas.go
Outdated
| util.CheckErr(err) | ||
| continue | ||
| } | ||
| //var client k8sdynamic.ResourceInterface |
There was a problem hiding this comment.
nit.. remove the commended line
pkg/resourceutils/updatereplicas.go
Outdated
| //resourceInterface := configClient.Resource() | ||
| //client = resourceInterface.Namespace(namespace) |
pkg/resourceutils/updatereplicas.go
Outdated
| } | ||
|
|
||
| // Get the CR | ||
| newParentResourceUnstructured, err := resourceClient.Get(context.TODO(), unstructuredObj.GetName(), metav1.GetOptions{}) |
There was a problem hiding this comment.
nit.. I think we should rename it and remove "parent". While reading the code it seemed like we are getting parentresource for the CR but it is not the case.
There was a problem hiding this comment.
Right, renamed it to "newResourceUnstructured"
pkg/resourceutils/updatereplicas.go
Outdated
| destPvcOwnersList := make([]metav1.OwnerReference, 0) | ||
| needUpdate := false | ||
| for _, pvcOwner := range pvc.GetOwnerReferences() { | ||
| if newOwnerUID, ok := newOwnerUIDMapping[fmt.Sprintf("%s-%s", pvcOwner.Name, pvcOwner.Kind)]; ok { |
There was a problem hiding this comment.
We are putting(name,namespace) as the key in newOwnerUIDMapping. But while fetching we are using (name, kind)
There was a problem hiding this comment.
good catch, fixed it now. thanks.
| excludeSelectors := make(map[string]string) | ||
| if migration.Spec.ExcludeSelectors != nil { | ||
| excludeSelectors = migration.Spec.ExcludeSelectors | ||
| excludeSelectors["stash-cr"] = "true" |
There was a problem hiding this comment.
nit: lets define stash-cr as a constant
| var dynamicClient dynamic.ResourceInterface | ||
| ownerName := "" | ||
| for _, o := range objects { | ||
| gkv := o.GetObjectKind().GroupVersionKind() |
| ownerName := "" | ||
| for _, o := range objects { | ||
| gkv := o.GetObjectKind().GroupVersionKind() | ||
| keyName := fmt.Sprintf("%v-%v-%v", gkv.Group, gkv.Kind, gkv.Version) |
There was a problem hiding this comment.
nit: may be write a helper function to get the key name for stashCRMap and use it in both the places.
| o.GetObjectKind().GroupVersionKind().GroupVersion().WithResource(resource.Name)) | ||
| } | ||
| } else { | ||
| log.MigrationLog(migration).Infof("getting configmap details for stashing resource %s/%s", unstructured.GetKind(), unstructured.GetName()) |
There was a problem hiding this comment.
nit: start log lines with upper-case
| } | ||
| // obj uid is not available and appending random uid will cause the next migration's get/delete of the configmap fail | ||
| // hence adding kind-name for cm name. | ||
| cmName := fmt.Sprintf("%s-%s", strings.ToLower(obj.GetKind()), obj.GetName()) |
There was a problem hiding this comment.
Ideally this should also be a helper function under pkg/utils/utils.go
| configMap.SetGroupVersionKind(schema.GroupVersionKind{ | ||
| Group: "", | ||
| Version: "v1", | ||
| Kind: "ConfigMap", | ||
| }) |
There was a problem hiding this comment.
+1 on this - would be easier to just create a corev1.ConfigMap objet and then convert it to unstructered.
| log.MigrationLog(migration).Infof("getting configmap details for stashing resource %s/%s", unstructured.GetKind(), unstructured.GetName()) | ||
| unstructured, err = getStashedConfigMap(unstructured) | ||
| if err != nil { | ||
| log.MigrationLog(migration).Warnf("unable to get stashed configmap content for object %s/%s, error: %v", unstructured.GetKind(), unstructured.GetName(), err) |
There was a problem hiding this comment.
That function returns an error only in case of json marshal which is unlikely to fail. But we should continue in the for loop and avoid going ahead in this function.
| configMap.Object["data"] = data | ||
| labels := map[string]string{"stash-cr": "true", "resource-kind": obj.GetKind()} | ||
| configMap.SetLabels(labels) | ||
| annotations := map[string]string{skipResourceAnnotation: "true", storkCreatedAnnotation: "true"} |
There was a problem hiding this comment.
We should also add the name of the object as a label
There was a problem hiding this comment.
Name max char allowed is 253 while for label's value it is 63.
Will put a key with name then to keep the full name information. Is it ok , @adityadani ?
There was a problem hiding this comment.
The CR name was added in configmap with a separate key.
|
|
||
| // Create the CR | ||
| _, err = resourceClient.Create(context.TODO(), unstructuredObj, metav1.CreateOptions{}) | ||
| if err != nil && !errors.IsAlreadyExists(err) { |
There was a problem hiding this comment.
If the error is already exists then should we log it on the CLI output?
There was a problem hiding this comment.
Fixed with a message hinting the resource exists.
f5c263c to
11d9578
Compare
11d9578 to
ea5a3a7
Compare
pp511
left a comment
There was a problem hiding this comment.
Mostly looks ok to me. Few comments and clarifications.
| Value string `json:"value"` | ||
| } | ||
|
|
||
| // StashStrategy to restrict CR applying during migration |
There was a problem hiding this comment.
nit. nit. CR applying -> applying CR
| // StashStrategy option will make sure as part of migration the CR does not get applied | ||
| // if StashCR is enabled. The CR will be applied as part of app activation |
There was a problem hiding this comment.
nit. nit...StashStrategy option if enabled will make sure CR does not get applied during migration.
| excludeSelectors[StashCRLabel] = "true" | ||
| } else { | ||
| excludeSelectors[StashCRLabel] = "true" |
There was a problem hiding this comment.
excludeSelectors[StashCRLabel] = "true" need not be inside if and else both. It can be outside these conditional statements.
| o.GetObjectKind().GroupVersionKind().GroupVersion().WithResource(resource.Name)) | ||
| } | ||
| } else { | ||
| log.MigrationLog(migration).Infof("Getting configmap details for stashing resource %s/%s", unstructured.GetKind(), unstructured.GetName()) |
There was a problem hiding this comment.
nit.. Why not print the version too?
There was a problem hiding this comment.
Same thing in the next statement too
| log.MigrationLog(migration).Infof("getting configmap details for stashing resource %s/%s", unstructured.GetKind(), unstructured.GetName()) | ||
| unstructured, err = getStashedConfigMap(unstructured) | ||
| if err != nil { | ||
| log.MigrationLog(migration).Warnf("unable to get stashed configmap content for object %s/%s, error: %v", unstructured.GetKind(), unstructured.GetName(), err) |
There was a problem hiding this comment.
We decided we will continue in the error case. This has not been addressed yet.
| } | ||
| // obj uid is not available and appending random uid will cause the next migration's get/delete of the configmap fail | ||
| // hence adding kind-name for cm name. | ||
| cmName := utils.GetStashedConfigMapName(strings.ToLower(obj.GetKind()), obj.GetName()) |
There was a problem hiding this comment.
I think we should include version too in the cmName. What do you think?
There was a problem hiding this comment.
Reverted this as version will contain "/" which is not allowed for configmap name.
| Namespace: obj.GetNamespace(), | ||
| Labels: map[string]string{ | ||
| StashCRLabel: "true", | ||
| "resource-kind": obj.GetKind(), |
There was a problem hiding this comment.
Why are we setting the resource-kind label here?
There was a problem hiding this comment.
This has been kept for debugging purpose.
| Data: map[string]string{ | ||
| StashedCMCRKey: string(jsonData), | ||
| StashedCMOwnedPVCKey: string(ownedPVCsEncoded), | ||
| "name": obj.GetName(), |
There was a problem hiding this comment.
nit..Why not have a constant for "name" too?
| return fmt.Sprintf("%v-%v-%v", group, kind, version) | ||
| } | ||
|
|
||
| func getStashedConfigMap(obj *unstructured.Unstructured, inputObjectHash uint64) (*unstructured.Unstructured, error) { |
There was a problem hiding this comment.
Ideally I would have expected core v1 . ConfigMap{} being returned from this function. But I see the you are trying to use the same worker to work for CM too. So I guess it's fine.
adityadani
left a comment
There was a problem hiding this comment.
Can you address the comments from the previous iteration?
| if _, ok := appRegsStashMap[keyName]; ok { | ||
| if appRegsStashMap[keyName] { |
There was a problem hiding this comment.
We don't need both the if conditions.
| if _, ok := appRegsStashMap[keyName]; ok { | ||
| stashCREnabled = appRegsStashMap[keyName] | ||
| } |
There was a problem hiding this comment.
| if _, ok := appRegsStashMap[keyName]; ok { | |
| stashCREnabled = appRegsStashMap[keyName] | |
| } | |
| stashCREnabled, _ = appRegsStashMap[keyName] |
ea5a3a7 to
49930f9
Compare
49930f9 to
029ca70
Compare
| excludeSelectors := make(map[string]string) | ||
| excludeSelectors[StashCRLabel] = "true" | ||
| if migration.Spec.ExcludeSelectors != nil { | ||
| excludeSelectors = migration.Spec.ExcludeSelectors | ||
| } |
There was a problem hiding this comment.
You always want to add the StashCRLabel to the exclude selectors right? Then on line 614 you will be overriding it with whatever the user has provided.
| excludeSelectors := make(map[string]string) | |
| excludeSelectors[StashCRLabel] = "true" | |
| if migration.Spec.ExcludeSelectors != nil { | |
| excludeSelectors = migration.Spec.ExcludeSelectors | |
| } | |
| if migration.Spec.ExcludeSelectors != nil { | |
| excludeSelectors = migration.Spec.ExcludeSelectors | |
| } else { | |
| excludeSelectors := make(map[string]string) | |
| } | |
| excludeSelectors[StashCRLabel] = "true" |
There was a problem hiding this comment.
you are right. now fixed it.
pkg/utils/utils.go
Outdated
| } | ||
|
|
||
| func GetStashedConfigMapName(apiVersion string, objKind string, objName string) string { | ||
| cmName := fmt.Sprintf("%s-%s-%s", apiVersion, objKind, objName) |
There was a problem hiding this comment.
Should we add group as well here since you are anyway trimming it? Esp the opensource DB operators have conflicting Kinds.
7415850 to
69b9990
Compare
e2069e1 to
70be3ea
Compare
PWX-32807: Compare hash objects of resources to avoid deletion and recreation in case of no change during the migration.
70be3ea to
781a3c0
Compare
What type of PR is this?
improvement
What this PR does / why we need it:
Stashing strategy for the CR content to a configmap so that after migration with
startApplication: Falsethe application automatically does not get started when it is managed by a clusterwide operator.Avoid recreating the resources during migration if there is no change to the resource content.
Does this PR change a user-facing CRD or CLI?:
Is a release note needed?:
Does this change need to be cherry-picked to a release branch?:
Test
Have been updated in PWX-31470 & PWX-32807.