1
0
mirror of https://github.com/rancher/norman.git synced 2025-09-03 08:14:40 +00:00

Refactor types

This commit is contained in:
Darren Shepherd
2017-11-29 14:27:02 -07:00
parent ee148b4d18
commit 15e105a0ab
15 changed files with 89 additions and 43 deletions

View File

@@ -12,8 +12,8 @@ var (
<!DOCTYPE html> <!DOCTYPE html>
<!-- If you are reading this, there is a good chance you would prefer sending an <!-- If you are reading this, there is a good chance you would prefer sending an
"Accept: application/json" header and receiving actual JSON responses. --> "Accept: application/json" header and receiving actual JSON responses. -->
<link rel="stylesheet" type="text/css" href="https://releases.rancher.com/api-ui/1.1.1/ui.min.css" /> <link rel="stylesheet" type="text/css" href="https://releases.rancher.com/api-ui/1.1.2/ui.min.css" />
<script src="https://releases.rancher.com/api-ui/1.1.1/ui.min.js"></script> <script src="https://releases.rancher.com/api-ui/1.1.2/ui.min.js"></script>
<script> <script>
var user = "admin"; var user = "admin";
var curlUser='${CATTLE_ACCESS_KEY}:${CATTLE_SECRET_KEY}'; var curlUser='${CATTLE_ACCESS_KEY}:${CATTLE_SECRET_KEY}';

View File

@@ -10,6 +10,7 @@ import (
"github.com/rancher/norman/parse" "github.com/rancher/norman/parse"
"github.com/rancher/norman/parse/builder" "github.com/rancher/norman/parse/builder"
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/definition"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -90,7 +91,7 @@ func toString(val interface{}) string {
} }
func (j *JSONResponseWriter) convert(b *builder.Builder, context *types.APIContext, input map[string]interface{}) *types.RawResource { func (j *JSONResponseWriter) convert(b *builder.Builder, context *types.APIContext, input map[string]interface{}) *types.RawResource {
schema := context.Schemas.Schema(context.Version, fmt.Sprint(input["type"])) schema := context.Schemas.Schema(context.Version, definition.GetFullType(input))
if schema == nil { if schema == nil {
return nil return nil
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/rancher/norman/api" "github.com/rancher/norman/api"
"github.com/rancher/norman/store/crd" "github.com/rancher/norman/store/crd"
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/factory"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
) )
@@ -29,7 +30,7 @@ var (
Path: "/example/v1", Path: "/example/v1",
} }
Schemas = types.NewSchemas() Schemas = factory.Schemas(&version)
) )
func main() { func main() {

View File

@@ -63,7 +63,7 @@ type {{.schema.CodeName}}Interface interface {
Get(name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error) Get(name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error)
Update(*{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error) Update(*{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
Delete(name string, options *metav1.DeleteOptions) error Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error) List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error)
Watch(opts metav1.ListOptions) (watch.Interface, error) Watch(opts metav1.ListOptions) (watch.Interface, error)
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error
Controller() {{.schema.CodeName}}Controller Controller() {{.schema.CodeName}}Controller
@@ -181,9 +181,9 @@ func (s *{{.schema.ID}}Client) Delete(name string, options *metav1.DeleteOptions
return s.objectClient.Delete(name, options) return s.objectClient.Delete(name, options)
} }
func (s *{{.schema.ID}}Client) List(opts metav1.ListOptions) (*{{.prefix}}{{.schema.CodeName}}List, error) { func (s *{{.schema.ID}}Client) List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error) {
obj, err := s.objectClient.List(opts) obj, err := s.objectClient.List(opts)
return obj.(*{{.prefix}}{{.schema.CodeName}}List), err return obj.(*{{.schema.CodeName}}List), err
} }
func (s *{{.schema.ID}}Client) Watch(opts metav1.ListOptions) (watch.Interface, error) { func (s *{{.schema.ID}}Client) Watch(opts metav1.ListOptions) (watch.Interface, error) {

View File

@@ -113,6 +113,10 @@ func (b *Builder) checkDefaultAndRequired(schema *types.Schema, input map[string
} }
} }
} }
if op == List && fieldMatchesOp(field, List) && definition.IsReferenceType(field.Type) && !hasKey {
result[fieldName] = nil
}
} }
return nil return nil
@@ -264,7 +268,7 @@ func (b *Builder) convertReferenceType(fieldType string, value interface{}) (str
func (b *Builder) convertArray(fieldType string, value interface{}, op Operation) ([]interface{}, error) { func (b *Builder) convertArray(fieldType string, value interface{}, op Operation) ([]interface{}, error) {
if strSliceValue, ok := value.([]string); ok { if strSliceValue, ok := value.([]string); ok {
// Form data will be []string // Form data will be []string
result := []interface{}{} var result []interface{}
for _, value := range strSliceValue { for _, value := range strSliceValue {
result = append(result, value) result = append(result, value)
} }

View File

@@ -6,7 +6,7 @@ import (
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/convert" "github.com/rancher/norman/types/convert"
"github.com/rancher/norman/types/mapper" "github.com/rancher/norman/types/values"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@@ -41,6 +41,11 @@ func NewProxyStore(k8sClient rest.Interface,
} }
func (p *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) { func (p *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
_, result, err := p.byID(apiContext, schema, id)
return result, err
}
func (p *Store) byID(apiContext *types.APIContext, schema *types.Schema, id string) (string, map[string]interface{}, error) {
namespace, id := splitID(id) namespace, id := splitID(id)
req := p.common(namespace, p.k8sClient.Get()). req := p.common(namespace, p.k8sClient.Get()).
@@ -132,11 +137,11 @@ func (p *Store) Create(apiContext *types.APIContext, schema *types.Schema, data
namespace, _ := data["namespaceId"].(string) namespace, _ := data["namespaceId"].(string)
p.toInternal(schema.Mapper, data) p.toInternal(schema.Mapper, data)
name, _ := mapper.GetValueN(data, "metadata", "name").(string) name, _ := values.GetValueN(data, "metadata", "name").(string)
if name == "" { if name == "" {
generated, _ := mapper.GetValueN(data, "metadata", "generateName").(string) generated, _ := values.GetValueN(data, "metadata", "generateName").(string)
if generated == "" { if generated == "" {
mapper.PutValue(data, strings.ToLower(schema.ID+"-"), "metadata", "generateName") values.PutValue(data, strings.ToLower(schema.ID+"-"), "metadata", "generateName")
} }
} }
@@ -145,7 +150,8 @@ func (p *Store) Create(apiContext *types.APIContext, schema *types.Schema, data
Object: data, Object: data,
}) })
return p.singleResult(schema, req) _, result, err := p.singleResult(schema, req)
return result, err
} }
func (p *Store) toInternal(mapper types.Mapper, data map[string]interface{}) { func (p *Store) toInternal(mapper types.Mapper, data map[string]interface{}) {
@@ -162,7 +168,7 @@ func (p *Store) toInternal(mapper types.Mapper, data map[string]interface{}) {
} }
func (p *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) { func (p *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
existing, err := p.ByID(apiContext, schema, id) resourceVersion, existing, err := p.byID(apiContext, schema, id)
if err != nil { if err != nil {
return data, nil return data, nil
} }
@@ -174,13 +180,16 @@ func (p *Store) Update(apiContext *types.APIContext, schema *types.Schema, data
p.toInternal(schema.Mapper, existing) p.toInternal(schema.Mapper, existing)
namespace, id := splitID(id) namespace, id := splitID(id)
values.PutValue(existing, resourceVersion, "metadata", "resourceVersion")
req := p.common(namespace, p.k8sClient.Put()). req := p.common(namespace, p.k8sClient.Put()).
Body(&unstructured.Unstructured{ Body(&unstructured.Unstructured{
Object: existing, Object: existing,
}). }).
Name(id) Name(id)
return p.singleResult(schema, req) _, result, err := p.singleResult(schema, req)
return result, err
} }
func (p *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) error { func (p *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) error {
@@ -196,15 +205,16 @@ func (p *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id st
return req.Do().Error() return req.Do().Error()
} }
func (p *Store) singleResult(schema *types.Schema, req *rest.Request) (map[string]interface{}, error) { func (p *Store) singleResult(schema *types.Schema, req *rest.Request) (string, map[string]interface{}, error) {
result := &unstructured.Unstructured{} result := &unstructured.Unstructured{}
err := req.Do().Into(result) err := req.Do().Into(result)
if err != nil { if err != nil {
return nil, err return "", nil, err
} }
version := result.GetResourceVersion()
p.fromInternal(schema, result.Object) p.fromInternal(schema, result.Object)
return result.Object, nil return version, result.Object, nil
} }
func splitID(id string) (string, string) { func splitID(id string) (string, string) {

View File

@@ -1,6 +1,10 @@
package definition package definition
import "strings" import (
"strings"
"github.com/rancher/norman/types/convert"
)
func IsMapType(fieldType string) bool { func IsMapType(fieldType string) bool {
return strings.HasPrefix(fieldType, "map[") && strings.HasSuffix(fieldType, "]") return strings.HasPrefix(fieldType, "map[") && strings.HasSuffix(fieldType, "]")
@@ -26,3 +30,12 @@ func SubType(fieldType string) string {
return fieldType[i+1 : len(fieldType)-1] return fieldType[i+1 : len(fieldType)-1]
} }
func GetType(data map[string]interface{}) string {
parts := strings.Split(GetFullType(data), "/")
return parts[len(parts)-1]
}
func GetFullType(data map[string]interface{}) string {
return convert.ToString(data["type"])
}

View File

@@ -8,12 +8,16 @@ import (
func Schemas(version *types.APIVersion) *types.Schemas { func Schemas(version *types.APIVersion) *types.Schemas {
s := types.NewSchemas() s := types.NewSchemas()
s.DefaultMappers = []types.Mapper{ s.DefaultMappers = func() []types.Mapper {
return []types.Mapper{
mapper.NewObject(), mapper.NewObject(),
} }
s.DefaultPostMappers = []types.Mapper{ }
s.DefaultPostMappers = func() []types.Mapper {
return []types.Mapper{
&mapper.RenameReference{}, &mapper.RenameReference{},
} }
}
s.AddMapperForType(version, v1.ObjectMeta{}, mapper.NewMetadataMapper()) s.AddMapperForType(version, v1.ObjectMeta{}, mapper.NewMetadataMapper())
return s return s
} }

View File

@@ -1,13 +1,16 @@
package mapper package mapper
import "github.com/rancher/norman/types" import (
"github.com/rancher/norman/types"
"github.com/rancher/norman/types/values"
)
type LabelField struct { type LabelField struct {
Field string Field string
} }
func (e LabelField) FromInternal(data map[string]interface{}) { func (e LabelField) FromInternal(data map[string]interface{}) {
v, ok := RemoveValue(data, "labels", "io.cattle.field."+e.Field) v, ok := values.RemoveValue(data, "labels", "io.cattle.field."+e.Field)
if ok { if ok {
data[e.Field] = v data[e.Field] = v
} }
@@ -16,7 +19,7 @@ func (e LabelField) FromInternal(data map[string]interface{}) {
func (e LabelField) ToInternal(data map[string]interface{}) { func (e LabelField) ToInternal(data map[string]interface{}) {
v, ok := data[e.Field] v, ok := data[e.Field]
if ok { if ok {
PutValue(data, v, "labels", "io.cattle.field."+e.Field) values.PutValue(data, v, "labels", "io.cattle.field."+e.Field)
} }
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/convert" "github.com/rancher/norman/types/convert"
"github.com/rancher/norman/types/definition" "github.com/rancher/norman/types/definition"
"github.com/rancher/norman/types/values"
) )
type Move struct { type Move struct {
@@ -17,14 +18,14 @@ type Move struct {
} }
func (m Move) FromInternal(data map[string]interface{}) { func (m Move) FromInternal(data map[string]interface{}) {
if v, ok := RemoveValue(data, strings.Split(m.From, "/")...); ok { if v, ok := values.RemoveValue(data, strings.Split(m.From, "/")...); ok {
PutValue(data, v, strings.Split(m.To, "/")...) values.PutValue(data, v, strings.Split(m.To, "/")...)
} }
} }
func (m Move) ToInternal(data map[string]interface{}) { func (m Move) ToInternal(data map[string]interface{}) {
if v, ok := RemoveValue(data, strings.Split(m.To, "/")...); ok { if v, ok := values.RemoveValue(data, strings.Split(m.To, "/")...); ok {
PutValue(data, v, strings.Split(m.From, "/")...) values.PutValue(data, v, strings.Split(m.From, "/")...)
} }
} }

View File

@@ -1,6 +1,8 @@
package mapper package mapper
import "github.com/rancher/norman/types" import (
"github.com/rancher/norman/types"
)
type Object struct { type Object struct {
types.Mappers types.Mappers
@@ -12,8 +14,8 @@ func NewObject(mappers ...types.Mapper) Object {
&Embed{Field: "metadata"}, &Embed{Field: "metadata"},
&Embed{Field: "spec", Optional: true}, &Embed{Field: "spec", Optional: true},
&ReadOnly{Field: "status", Optional: true}, &ReadOnly{Field: "status", Optional: true},
&Drop{"kind"}, Drop{"kind"},
&Drop{"apiVersion"}, Drop{"apiVersion"},
&Scope{ &Scope{
IfNot: types.NamespaceScope, IfNot: types.NamespaceScope,
Mappers: []types.Mapper{ Mappers: []types.Mapper{

View File

@@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/rancher/norman/types" "github.com/rancher/norman/types"
"github.com/rancher/norman/types/values"
) )
type SetValue struct { type SetValue struct {
@@ -15,24 +16,24 @@ type SetValue struct {
} }
func (s SetValue) FromInternal(data map[string]interface{}) { func (s SetValue) FromInternal(data map[string]interface{}) {
v, ok := GetValue(data, strings.Split(s.From, "/")...) v, ok := values.GetValue(data, strings.Split(s.From, "/")...)
if !ok { if !ok {
return return
} }
if v == s.IfEq { if v == s.IfEq {
PutValue(data, s.Value, strings.Split(s.To, "/")...) values.PutValue(data, s.Value, strings.Split(s.To, "/")...)
} }
} }
func (s SetValue) ToInternal(data map[string]interface{}) { func (s SetValue) ToInternal(data map[string]interface{}) {
v, ok := GetValue(data, strings.Split(s.To, "/")...) v, ok := values.GetValue(data, strings.Split(s.To, "/")...)
if !ok { if !ok {
return return
} }
if v == s.Value { if v == s.Value {
PutValue(data, s.IfEq, strings.Split(s.From, "/")...) values.PutValue(data, s.IfEq, strings.Split(s.From, "/")...)
} }
} }

View File

@@ -142,10 +142,14 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r
} }
mappers := s.mapper(&schema.Version, schema.ID) mappers := s.mapper(&schema.Version, schema.ID)
if s.DefaultMappers != nil {
if schema.CanList() { if schema.CanList() {
mappers = append(s.DefaultMappers, mappers...) mappers = append(s.DefaultMappers(), mappers...)
}
}
if s.DefaultPostMappers != nil {
mappers = append(mappers, s.DefaultPostMappers()...)
} }
mappers = append(mappers, s.DefaultPostMappers...)
if len(mappers) > 0 { if len(mappers) > 0 {
copy, err := s.newSchemaFromType(version, t, typeName) copy, err := s.newSchemaFromType(version, t, typeName)

View File

@@ -15,12 +15,14 @@ type SchemaCollection struct {
type SchemaInitFunc func(*Schemas) *Schemas type SchemaInitFunc func(*Schemas) *Schemas
type MappersFactory func() []Mapper
type Schemas struct { type Schemas struct {
schemasByPath map[string]map[string]*Schema schemasByPath map[string]map[string]*Schema
schemasBySubContext map[string]*Schema schemasBySubContext map[string]*Schema
mappers map[string]map[string][]Mapper mappers map[string]map[string][]Mapper
DefaultMappers []Mapper DefaultMappers MappersFactory
DefaultPostMappers []Mapper DefaultPostMappers MappersFactory
versions []APIVersion versions []APIVersion
schemas []*Schema schemas []*Schema
errors []error errors []error

View File

@@ -1,4 +1,4 @@
package mapper package values
func RemoveValue(data map[string]interface{}, keys ...string) (interface{}, bool) { func RemoveValue(data map[string]interface{}, keys ...string) (interface{}, bool) {
for i, key := range keys { for i, key := range keys {