Skip to content

Commit

Permalink
Fix deleting keys in maps
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuildthecloud committed Apr 23, 2018
1 parent 0611d5f commit f783799
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 94 deletions.
3 changes: 2 additions & 1 deletion store/proxy/proxy_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand Down
88 changes: 0 additions & 88 deletions types/convert/merge.go

This file was deleted.

117 changes: 117 additions & 0 deletions types/convert/merge/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
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))
} 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 mergeMetadata(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
result := copyMap(dest)

labels := mergeMaps(nil, nil, convert.ToMapInterface(dest["labels"]), convert.ToMapInterface(src["labels"]))

existingAnnotation := convert.ToMapInterface(dest["annotations"])
newAnnotation := convert.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(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
}
return schemas.Schema(&schema.Version, schema.ResourceFields[field].Type)
}

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
}
8 changes: 3 additions & 5 deletions types/server_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit f783799

Please sign in to comment.