mirror of
https://github.com/rancher/steve.git
synced 2025-04-28 19:24:42 +00:00
118 lines
4.0 KiB
Go
118 lines
4.0 KiB
Go
package definitions
|
|
|
|
import (
|
|
"k8s.io/kube-openapi/pkg/util/proto"
|
|
)
|
|
|
|
// schemaFieldVisitor implements proto.SchemaVisitor and turns a given schema into a definitionField.
|
|
type schemaFieldVisitor struct {
|
|
field definitionField
|
|
definitions map[string]definition
|
|
}
|
|
|
|
// VisitArray turns an array into a definitionField (stored on the receiver). For arrays of complex types, will also
|
|
// visit the subtype.
|
|
func (s *schemaFieldVisitor) VisitArray(array *proto.Array) {
|
|
field := definitionField{
|
|
Description: array.GetDescription(),
|
|
}
|
|
// this currently is not recursive and provides little information for nested types- while this isn't optimal,
|
|
// it was kept this way to provide backwards compat with previous endpoints.
|
|
array.SubType.Accept(s)
|
|
subField := s.field
|
|
field.Type = "array"
|
|
field.SubType = subField.Type
|
|
s.field = field
|
|
}
|
|
|
|
// VisitMap turns a map into a definitionField (stored on the receiver). For maps of complex types, will also visit the
|
|
// subtype.
|
|
func (s *schemaFieldVisitor) VisitMap(protoMap *proto.Map) {
|
|
field := definitionField{
|
|
Description: protoMap.GetDescription(),
|
|
}
|
|
// this currently is not recursive and provides little information for nested types- while this isn't optimal,
|
|
// it was kept this way to provide backwards compat with previous endpoints.
|
|
protoMap.SubType.Accept(s)
|
|
subField := s.field
|
|
field.Type = "map"
|
|
field.SubType = subField.Type
|
|
s.field = field
|
|
}
|
|
|
|
// VisitPrimitive turns a primitive into a definitionField (stored on the receiver).
|
|
func (s *schemaFieldVisitor) VisitPrimitive(primitive *proto.Primitive) {
|
|
field := definitionField{
|
|
Description: primitive.GetDescription(),
|
|
}
|
|
field.Type = getPrimitiveType(primitive.Type)
|
|
s.field = field
|
|
}
|
|
|
|
// VisitKind turns a kind into a definitionField and a definition. Both are stored on the receiver.
|
|
func (s *schemaFieldVisitor) VisitKind(kind *proto.Kind) {
|
|
path := kind.Path.String()
|
|
field := definitionField{
|
|
Description: kind.GetDescription(),
|
|
Type: path,
|
|
}
|
|
if _, ok := s.definitions[path]; ok {
|
|
// if we have already seen this kind, we don't want to re-evaluate the definition. Some kinds can be
|
|
// recursive through use of references, so this circuit-break is necessary to avoid infinite loops
|
|
s.field = field
|
|
return
|
|
}
|
|
schemaDefinition := definition{
|
|
ResourceFields: map[string]definitionField{},
|
|
Type: path,
|
|
Description: kind.GetDescription(),
|
|
}
|
|
// this definition may refer to itself, so we mark this as seen to not infinitely recurse
|
|
s.definitions[path] = definition{}
|
|
for fieldName, schemaField := range kind.Fields {
|
|
schemaField.Accept(s)
|
|
schemaDefinition.ResourceFields[fieldName] = s.field
|
|
}
|
|
for _, field := range kind.RequiredFields {
|
|
current, ok := schemaDefinition.ResourceFields[field]
|
|
if !ok {
|
|
// this does silently ignore inconsistent kinds that list
|
|
continue
|
|
}
|
|
current.Required = true
|
|
schemaDefinition.ResourceFields[field] = current
|
|
}
|
|
s.definitions[path] = schemaDefinition
|
|
// the visitor may have set the field multiple times while evaluating kind fields, so we only set the final
|
|
// kind-based field at the end
|
|
s.field = field
|
|
}
|
|
|
|
// VisitReference turns a reference into a definitionField. Will also visit the referred type.
|
|
func (s *schemaFieldVisitor) VisitReference(ref proto.Reference) {
|
|
sub := ref.SubSchema()
|
|
if sub == nil {
|
|
// if we don't have a sub-schema defined, we can't extract much meaningful information
|
|
field := definitionField{
|
|
Description: ref.GetDescription(),
|
|
Type: ref.Reference(),
|
|
}
|
|
s.field = field
|
|
return
|
|
}
|
|
sub.Accept(s)
|
|
field := s.field
|
|
field.Description = ref.GetDescription()
|
|
s.field = field
|
|
}
|
|
|
|
// VisitArbitrary turns an abitrary (item with no type) into a definitionField (stored on the receiver).
|
|
func (s *schemaFieldVisitor) VisitArbitrary(arb *proto.Arbitrary) {
|
|
// In certain cases k8s seems to not provide a type for certain fields. We assume for the
|
|
// purposes of this visitor that all of these have a type of string.
|
|
s.field = definitionField{
|
|
Description: arb.GetDescription(),
|
|
Type: "string",
|
|
}
|
|
}
|