diff --git a/pkg/schema/converter/openapi.go b/pkg/schema/converter/openapi.go index 1960f55..6c25554 100644 --- a/pkg/schema/converter/openapi.go +++ b/pkg/schema/converter/openapi.go @@ -47,6 +47,13 @@ func modelToSchema(modelName string, k *proto.Kind) *types.APISchema { } } + for k, v := range s.ResourceFields { + if types.ReservedFields[k] { + s.ResourceFields["_"+k] = v + delete(s.ResourceFields, k) + } + } + return &s } diff --git a/pkg/schema/converter/openapiv3.go b/pkg/schema/converter/openapiv3.go index cd49f9d..d5b15a8 100644 --- a/pkg/schema/converter/openapiv3.go +++ b/pkg/schema/converter/openapiv3.go @@ -31,6 +31,13 @@ func modelV3ToSchema(name string, k *v1beta1.JSONSchemaProps, schemasMap map[str schemasMap[s.ID] = &s } + for k, v := range s.ResourceFields { + if types.ReservedFields[k] { + s.ResourceFields["_"+k] = v + delete(s.ResourceFields, k) + } + } + return &s } diff --git a/pkg/schemaserver/types/types.go b/pkg/schemaserver/types/types.go index 98b8e84..f46bfb9 100644 --- a/pkg/schemaserver/types/types.go +++ b/pkg/schemaserver/types/types.go @@ -59,6 +59,13 @@ type NamedResourceCollection struct { Data []NamedResource `json:"data,omitempty"` } +var ReservedFields = map[string]bool{ + "id": true, + "type": true, + "links": true, + "actions": true, +} + type APISchema struct { *schemas.Schema diff --git a/pkg/server/store/proxy/proxy_store.go b/pkg/server/store/proxy/proxy_store.go index 9fb1300..a4e83c4 100644 --- a/pkg/server/store/proxy/proxy_store.go +++ b/pkg/server/store/proxy/proxy_store.go @@ -1,6 +1,7 @@ package proxy import ( + "encoding/json" "fmt" "io" "io/ioutil" @@ -57,6 +58,10 @@ func toAPI(schema *types.APISchema, obj runtime.Object) types.APIObject { return types.APIObject{} } + if unstr, ok := obj.(*unstructured.Unstructured); ok { + obj = moveToUnderscore(unstr) + } + gvr := attributes.GVR(schema) t := fmt.Sprintf("%s/%s/%s", gvr.Group, gvr.Version, gvr.Resource) @@ -94,6 +99,37 @@ func (s *Store) byID(apiOp *types.APIRequest, schema *types.APISchema, id string return k8sClient.Get(id, opts) } +func moveFromUnderscore(obj map[string]interface{}) map[string]interface{} { + if obj == nil { + return nil + } + for k := range types.ReservedFields { + v, ok := obj["_"+k] + delete(obj, "_"+k) + delete(obj, k) + if ok { + obj[k] = v + } + } + return obj +} + +func moveToUnderscore(obj *unstructured.Unstructured) *unstructured.Unstructured { + if obj == nil { + return nil + } + + for k := range types.ReservedFields { + v, ok := obj.Object[k] + if ok { + delete(obj.Object, k) + obj.Object["_"+k] = v + } + } + + return obj +} + func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) { k8sClient, err := s.clientGetter.Client(apiOp, schema, apiOp.Namespace) if err != nil { @@ -270,6 +306,18 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params return types.APIObject{}, err } + if pType == apitypes.StrategicMergePatchType { + data := map[string]interface{}{} + if err := json.Unmarshal(bytes, &data); err != nil { + return types.APIObject{}, err + } + data = moveFromUnderscore(data) + bytes, err = json.Marshal(data) + if err != nil { + return types.APIObject{}, err + } + } + resp, err := k8sClient.Patch(id, pType, bytes, opts) if err != nil { return types.APIObject{}, err @@ -288,7 +336,7 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, params return types.APIObject{}, err } - resp, err := k8sClient.Update(&unstructured.Unstructured{Object: input}, metav1.UpdateOptions{}) + resp, err := k8sClient.Update(&unstructured.Unstructured{Object: moveFromUnderscore(input)}, metav1.UpdateOptions{}) if err != nil { return types.APIObject{}, err }