diff --git a/apis/cluster.cattle.io/v3/schema/schema.go b/apis/cluster.cattle.io/v3/schema/schema.go index e7755b21..b5b1ceed 100644 --- a/apis/cluster.cattle.io/v3/schema/schema.go +++ b/apis/cluster.cattle.io/v3/schema/schema.go @@ -5,6 +5,7 @@ import ( m "github.com/rancher/norman/types/mapper" "github.com/rancher/types/factory" "k8s.io/api/core/v1" + "k8s.io/api/storage/v1beta1" ) var ( @@ -18,7 +19,8 @@ var ( Schemas = factory.Schemas(&Version). Init(namespaceTypes). - Init(volumeTypes) + Init(persistentVolumeTypes). + Init(storageClassTypes) ) func namespaceTypes(schemas *types.Schemas) *types.Schemas { @@ -37,7 +39,14 @@ func namespaceTypes(schemas *types.Schemas) *types.Schemas { }{}) } -func volumeTypes(schemas *types.Schemas) *types.Schemas { +func persistentVolumeTypes(schemas *types.Schemas) *types.Schemas { return schemas. MustImport(&Version, v1.PersistentVolume{}) } + +func storageClassTypes(schemas *types.Schemas) *types.Schemas { + return schemas. + MustImport(&Version, v1beta1.StorageClass{}, struct { + ReclaimPolicy string `json:"reclaimPolicy,omitempty" norman:"type=enum,options=Recycle|Delete|Retain"` + }{}) +} diff --git a/apis/project.cattle.io/v3/schema/schema.go b/apis/project.cattle.io/v3/schema/schema.go index f9195ba9..e9f8860c 100644 --- a/apis/project.cattle.io/v3/schema/schema.go +++ b/apis/project.cattle.io/v3/schema/schema.go @@ -572,6 +572,25 @@ func ingressTypes(schemas *types.Schemas) *types.Schemas { func volumeTypes(schemas *types.Schemas) *types.Schemas { return schemas. + AddMapperForType(&Version, v1.ResourceRequirements{}, + mapper.PivotMapper{Plural: true}, + ). + AddMapperForType(&Version, v1.PersistentVolumeClaimVolumeSource{}, + &m.Move{From: "claimName", To: "persistentVolumeClaimName"}, + ). + MustImport(&Version, v1.PersistentVolumeClaimVolumeSource{}, struct { + ClaimName string `norman:"type=reference[persistentVolumeClaim]"` + }{}). + MustImport(&Version, v1.SecretVolumeSource{}, struct { + SecretName string `norman:"type=reference[secret]"` + }{}). + MustImport(&Version, v1.Volume{}, struct { + }{}). + MustImport(&Version, v1.PersistentVolumeClaimSpec{}, struct { + AccessModes []string `json:"accessModes,omitempty" norman:"type=array[enum],options=ReadWriteOnce|ReadOnlyMany|ReadWriteMany"` + VolumeName string `json:"volumeName,omitempty" norman:"type=reference[/v3/cluster/persistentVolume]"` + StorageClassName *string `json:"storageClassName,omitempty" norman:"type=reference[/v3/cluster/storageClass]"` + }{}). MustImport(&Version, v1.PersistentVolumeClaim{}, projectOverride{}) } diff --git a/factory/schemas.go b/factory/schemas.go index 2124f079..cfb4d164 100644 --- a/factory/schemas.go +++ b/factory/schemas.go @@ -19,6 +19,8 @@ func Schemas(version *types.APIVersion) *types.Schemas { Mappers: []types.Mapper{ &mapper.NamespaceIDMapper{}, }, + }, &mapper.NamespaceReference{ + VersionPath: "/v3/project", }) return mappers } diff --git a/mapper/namespace_reference.go b/mapper/namespace_reference.go new file mode 100644 index 00000000..09abddeb --- /dev/null +++ b/mapper/namespace_reference.go @@ -0,0 +1,79 @@ +package mapper + +import ( + "strings" + + "fmt" + + "github.com/rancher/norman/types" + "github.com/rancher/norman/types/convert" + "github.com/rancher/norman/types/definition" +) + +type NamespaceReference struct { + fields [][]string + VersionPath string +} + +func (n *NamespaceReference) FromInternal(data map[string]interface{}) { + namespaceID, ok := data["namespaceId"] + if ok { + for _, path := range n.fields { + convert.Transform(data, path, func(input interface{}) interface{} { + return fmt.Sprintf("%s:%v", namespaceID, input) + }) + } + } +} + +func (n *NamespaceReference) ToInternal(data map[string]interface{}) { + for _, path := range n.fields { + convert.Transform(data, path, func(input interface{}) interface{} { + return strings.SplitN(convert.ToString(input), ":", 2)[0] + }) + } +} + +func (n *NamespaceReference) ModifySchema(schema *types.Schema, schemas *types.Schemas) error { + _, hasNamespace := schema.ResourceFields["namespaceId"] + if schema.Version.Path != n.VersionPath || !hasNamespace { + return nil + } + n.fields = traverse(nil, schema, schemas) + return nil +} + +func traverse(prefix []string, schema *types.Schema, schemas *types.Schemas) [][]string { + var result [][]string + + for name, field := range schema.ResourceFields { + localPrefix := []string{name} + subType := field.Type + if definition.IsArrayType(field.Type) { + localPrefix = append(localPrefix, "{ARRAY}") + subType = definition.SubType(field.Type) + } else if definition.IsMapType(field.Type) { + localPrefix = append(localPrefix, "{MAP}") + subType = definition.SubType(field.Type) + } + if definition.IsReferenceType(subType) { + result = appendReference(result, prefix, localPrefix, field, schema, schemas) + continue + } + + subSchema := schemas.Schema(&schema.Version, subType) + if subSchema != nil { + result = append(result, traverse(append(prefix, localPrefix...), subSchema, schemas)...) + } + } + + return result +} + +func appendReference(result [][]string, prefix []string, name []string, field types.Field, schema *types.Schema, schemas *types.Schemas) [][]string { + targetSchema := schemas.Schema(&schema.Version, definition.SubType(field.Type)) + if targetSchema != nil && targetSchema.Scope == types.NamespaceScope { + result = append(result, append(prefix, name...)) + } + return result +}