mirror of
https://github.com/rancher/norman.git
synced 2025-07-07 20:39:52 +00:00
Fix deleting keys in maps
This commit is contained in:
parent
0611d5f7a1
commit
db37c4223d
@ -10,6 +10,7 @@ import (
|
||||
"github.com/rancher/norman/restwatch"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/convert/merge"
|
||||
"github.com/rancher/norman/types/values"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
@ -326,7 +327,7 @@ func (p *Store) Update(apiContext *types.APIContext, schema *types.Schema, data
|
||||
}
|
||||
|
||||
p.toInternal(schema.Mapper, data)
|
||||
existing = convert.APIUpdateMerge(existing, data, apiContext.Query.Get("_replace") == "true")
|
||||
existing = merge.APIUpdateMerge(schema.InternalSchema, apiContext.Schemas, existing, data, apiContext.Query.Get("_replace") == "true")
|
||||
|
||||
values.PutValue(existing, resourceVersion, "metadata", "resourceVersion")
|
||||
values.PutValue(existing, namespace, "metadata", "namespace")
|
||||
|
@ -1,88 +0,0 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func APIUpdateMerge(dest, src map[string]interface{}, replace bool) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
if replace {
|
||||
if status, ok := dest["status"]; ok {
|
||||
result["status"] = status
|
||||
}
|
||||
if metadata, ok := dest["metadata"]; ok {
|
||||
result["metadata"] = metadata
|
||||
}
|
||||
} else {
|
||||
result = copyMap(dest)
|
||||
}
|
||||
|
||||
for k, v := range src {
|
||||
if k == "metadata" {
|
||||
result["metadata"] = mergeMetadata(ToMapInterface(dest["metadata"]), ToMapInterface(v))
|
||||
} else if k == "status" {
|
||||
continue
|
||||
}
|
||||
|
||||
existing, ok := dest[k]
|
||||
if ok && !replace {
|
||||
result[k] = merge(existing, v)
|
||||
} else {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeMetadata(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
|
||||
result := copyMap(dest)
|
||||
|
||||
labels := mergeMaps(ToMapInterface(dest["labels"]), ToMapInterface(src["labels"]))
|
||||
|
||||
existingAnnotation := ToMapInterface(dest["annotations"])
|
||||
newAnnotation := ToMapInterface(src["annotations"])
|
||||
annotations := copyMap(existingAnnotation)
|
||||
|
||||
for k, v := range newAnnotation {
|
||||
if strings.Contains(k, "cattle.io/") {
|
||||
continue
|
||||
}
|
||||
annotations[k] = v
|
||||
}
|
||||
for k, v := range existingAnnotation {
|
||||
if strings.Contains(k, "cattle.io/") {
|
||||
annotations[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
result["labels"] = labels
|
||||
result["annotations"] = annotations
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func merge(dest, src interface{}) interface{} {
|
||||
sm, smOk := src.(map[string]interface{})
|
||||
dm, dmOk := dest.(map[string]interface{})
|
||||
if smOk && dmOk {
|
||||
return mergeMaps(dm, sm)
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func mergeMaps(dest map[string]interface{}, src map[string]interface{}) interface{} {
|
||||
result := copyMap(dest)
|
||||
for k, v := range src {
|
||||
result[k] = merge(dest[k], v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func copyMap(src map[string]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range src {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
138
types/convert/merge/merge.go
Normal file
138
types/convert/merge/merge.go
Normal file
@ -0,0 +1,138 @@
|
||||
package merge
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func APIUpdateMerge(schema *types.Schema, schemas *types.Schemas, dest, src map[string]interface{}, replace bool) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
if replace {
|
||||
if status, ok := dest["status"]; ok {
|
||||
result["status"] = status
|
||||
}
|
||||
if metadata, ok := dest["metadata"]; ok {
|
||||
result["metadata"] = metadata
|
||||
}
|
||||
} else {
|
||||
result = copyMap(dest)
|
||||
}
|
||||
|
||||
for k, v := range src {
|
||||
if k == "metadata" {
|
||||
result["metadata"] = mergeMetadata(convert.ToMapInterface(dest["metadata"]), convert.ToMapInterface(v))
|
||||
continue
|
||||
} else if k == "status" {
|
||||
continue
|
||||
}
|
||||
|
||||
existing, ok := dest[k]
|
||||
if ok && !replace {
|
||||
result[k] = merge(k, schema, schemas, existing, v)
|
||||
} else {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeProtected(dest, src map[string]interface{}) map[string]interface{} {
|
||||
if src == nil {
|
||||
return dest
|
||||
}
|
||||
|
||||
result := copyMap(dest)
|
||||
|
||||
for k, v := range src {
|
||||
if strings.Contains(k, "cattle.io/") {
|
||||
continue
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
for k := range dest {
|
||||
if strings.Contains(k, "cattle.io/") {
|
||||
continue
|
||||
}
|
||||
if _, ok := src[k]; !ok {
|
||||
delete(dest, k)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeMetadata(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
|
||||
result := copyMap(dest)
|
||||
|
||||
labels := convert.ToMapInterface(dest["labels"])
|
||||
srcLabels := convert.ToMapInterface(src["labels"])
|
||||
labels = mergeProtected(labels, srcLabels)
|
||||
|
||||
annotations := convert.ToMapInterface(dest["annotations"])
|
||||
srcAnnotation := convert.ToMapInterface(src["annotations"])
|
||||
annotations = mergeProtected(annotations, srcAnnotation)
|
||||
|
||||
result["labels"] = labels
|
||||
result["annotations"] = annotations
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func merge(field string, schema *types.Schema, schemas *types.Schemas, dest, src interface{}) interface{} {
|
||||
if dest == nil {
|
||||
return src
|
||||
}
|
||||
if src == nil {
|
||||
return dest
|
||||
}
|
||||
|
||||
if isMap(field, schema) {
|
||||
return src
|
||||
}
|
||||
|
||||
sm, smOk := src.(map[string]interface{})
|
||||
dm, dmOk := dest.(map[string]interface{})
|
||||
if smOk && dmOk {
|
||||
return mergeMaps(getSchema(field, schema, schemas), schemas, dm, sm)
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func getSchema(field string, schema *types.Schema, schemas *types.Schemas) *types.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
s := schemas.Schema(&schema.Version, schema.ResourceFields[field].Type)
|
||||
if s != nil && s.InternalSchema != nil {
|
||||
return s.InternalSchema
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func isMap(field string, schema *types.Schema) bool {
|
||||
if schema == nil {
|
||||
return false
|
||||
}
|
||||
f := schema.ResourceFields[field]
|
||||
return strings.HasPrefix(f.Type, "map[")
|
||||
}
|
||||
|
||||
func mergeMaps(schema *types.Schema, schemas *types.Schemas, dest map[string]interface{}, src map[string]interface{}) interface{} {
|
||||
result := copyMap(dest)
|
||||
for k, v := range src {
|
||||
result[k] = merge(k, schema, schemas, dest[k], v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func copyMap(src map[string]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range src {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
@ -95,11 +95,9 @@ type APIContext struct {
|
||||
ResponseWriter ResponseWriter
|
||||
QueryFilter QueryFilter
|
||||
SubContextAttributeProvider SubContextAttributeProvider
|
||||
//QueryOptions *QueryOptions
|
||||
URLBuilder URLBuilder
|
||||
AccessControl AccessControl
|
||||
SubContext map[string]string
|
||||
//Attributes map[string]interface{}
|
||||
URLBuilder URLBuilder
|
||||
AccessControl AccessControl
|
||||
SubContext map[string]string
|
||||
|
||||
Request *http.Request
|
||||
Response http.ResponseWriter
|
||||
|
Loading…
Reference in New Issue
Block a user