1
0
mirror of https://github.com/rancher/norman.git synced 2025-07-07 12:29:10 +00:00

Fix deleting keys in maps

This commit is contained in:
Darren Shepherd 2018-04-22 22:20:38 -07:00
parent 0611d5f7a1
commit db37c4223d
4 changed files with 143 additions and 94 deletions

View File

@ -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")

View File

@ -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
}

View 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
}

View File

@ -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