Core The Basics

Object

Overview

The Object instances are as follows. They are basically in the pkg/apis directory, you can find it yourself.

Unstructured

The scene of Unstructured and Object cooperation is as follows.

The example diagram is as follows.

Scheme

Builder

Scheme

Look at the definition of Scheme, the first four are maintained the relationship between reflect.Type and Schema.GroupVersionKind. The defaulterFuncs is used to build a default object.

type Scheme struct {
    // versionMap allows one to figure out the go type of an object with
    // the given version and name.
    gvkToType map[schema.GroupVersionKind]reflect.Type

    // typeToGroupVersion allows one to find metadata for a given go object.
    // The reflect.Type we index by should *not* be a pointer.
    typeToGVK map[reflect.Type][]schema.GroupVersionKind

    // unversionedTypes are transformed without conversion in ConvertToVersion.
    unversionedTypes map[reflect.Type]schema.GroupVersionKind

    // unversionedKinds are the names of kinds that can be created in the context of any group
    // or version
    // TODO: resolve the status of unversioned types.
    unversionedKinds map[string]reflect.Type

    // Map from version and resource to the corresponding func to convert
    // resource field labels in that version to internal version.
    fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc

    // defaulterFuncs is an array of interfaces to be called with an object to provide defaulting
    // the provided object must be a pointer.
    defaulterFuncs map[reflect.Type]func(interface{})

    // converter stores all registered conversion functions. It also has
    // default converting behavior.
    converter *conversion.Converter

    // versionPriority is a map of groups to ordered lists of versions for those groups indicating the
    // default priorities of these versions as registered in the scheme
    versionPriority map[string][]string

    // observedVersions keeps track of the order we've seen versions during type registration
    observedVersions []schema.GroupVersion

    // schemeName is the name of this scheme.  If you don't specify a name, the stack of the NewScheme caller will be used.
    // This is useful for error reporting to indicate the origin of the scheme.
    schemeName string
}

FieldLabelConversionFunc is used to convert label and value to internal label and value.

type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)

AddKnownTypes

AddKnownTypes only needs to pay attention to one problem, that is, the GroupVersionKind is generated from the incoming GroupVersion through the Name method of reflect.Type as the Kind. Please see the simplified sample Reflect Name Sample. The sample code can be executed under Go Playground.

AddUnversionedTypes

The principle of AddUnversionedTypes is as follows. Unversioned Type can be understood as an Object mounted on a Group, and the Version will never be updated.

nameFunc

The principle of nameFunc is as follows, just pay attention to the return type priority to Internal Type.

Others

Conversion

Landscape

The typePair is used to represent the combination of source type and target type, typeNamePair stores the type and type name. DefaultNameFunc is used as the conversion method from the default type to Name. ConversionFunc defines the object conversion method.

Core Function Definitions

The DefaultNameFunc implementation is as follows.

var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }

The ConversionFunc declaration is as follows.

type ConversionFunc func(a, b interface{}, scope Scope) error

FieldMappingFunc converts the key to Field in the source structure and the target structure.

type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)

ConversionFuncs

Converter

Briefly explain the following methods:

doConversion

When Converter executes object conversion methods, such as Convert and DefaultConvert, it is allowed to pass in a Meta object and execute the doConversion method to construct the scope object in this method.

Scope

defaultConvert

The defaultConvert handles the default type conversion, the incoming sv, dv have been ensured to be addressable through EnforcePtr. This part of the code is a nearly perfect application of the reflect package in Go.

First, deal with the conversion of basic types, which can be converted by AssignableTo or ConvertibleTo.

switch st.Kind() {
    case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
    // 这些类型后续处理
    default:
    // This should handle all simple types.
    if st.AssignableTo(dt) {
        dv.Set(sv)
        return nil
    }
    if st.ConvertibleTo(dt) {
        dv.Set(sv.Convert(dt))
        return nil
    }
}

Then process them separately according to dv.Kind().

dv.Kind() -> reflect.Struct

Return the result of the convertKV method directly. However, you need to pay attention to first convert sv and dv into the form of Key/Value respectively. Please study the toKVValue method by yourself.

return c.convertKV(toKVValue(sv), toKVValue(dv), scope)

dv.Kind() -> reflect.Slice

case reflect.Slice:
    if sv.IsNil() {
        // Don't make a zero-length slice.
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
    for i := 0; i < sv.Len(); i++ {
        scope.setIndices(i, i)
        if err := c.convert(sv.Index(i), dv.Index(i), scope); err != nil {
            return err
        }
    }

dv.Kind() -> reflect.Ptr

case reflect.Ptr:
    if sv.IsNil() {
        // Don't copy a nil ptr!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.New(dt.Elem()))
    switch st.Kind() {
        case reflect.Ptr, reflect.Interface:
        return c.convert(sv.Elem(), dv.Elem(), scope)
        default:
        return c.convert(sv, dv.Elem(), scope)
    }

dv.Kind() -> reflect.Interface

case reflect.Interface:
    if sv.IsNil() {
        // Don't copy a nil interface!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    tmpdv := reflect.New(sv.Elem().Type()).Elem()
    if err := c.convert(sv.Elem(), tmpdv, scope); err != nil {
        return err
    }
    dv.Set(reflect.ValueOf(tmpdv.Interface()))
    return nil

dv.Kind() -> reflect.Map

case reflect.Map:
    if sv.IsNil() {
        // Don't copy a nil ptr!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.MakeMap(dt))
    for _, sk := range sv.MapKeys() {
        dk := reflect.New(dt.Key()).Elem()
        if err := c.convert(sk, dk, scope); err != nil {
            return err
        }
        dkv := reflect.New(dt.Elem()).Elem()
        scope.setKeys(sk.Interface(), dk.Interface())

        if err := c.convert(sv.MapIndex(sk), dkv, scope); err != nil {
            return err
        }
        dv.SetMapIndex(dk, dkv)
    }

Last updated