123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package parse
- import (
- "fmt"
- "reflect"
- "k8s.io/kube-openapi/pkg/util/proto"
- "k8s.io/kubernetes/pkg/kubectl/apply"
- "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
- )
- // Factory creates an Element by combining object values from recorded, local and remote sources with
- // the metadata from an openapi schema.
- type Factory struct {
- // Resources contains the openapi field metadata for the object models
- Resources openapi.Resources
- }
- // CreateElement returns an Element by collating the recorded, local and remote field values
- func (b *Factory) CreateElement(recorded, local, remote map[string]interface{}) (apply.Element, error) {
- // Create an Item from the 3 values. Use empty name for field
- visitor := &ElementBuildingVisitor{b.Resources}
- gvk, err := getCommonGroupVersionKind(recorded, local, remote)
- if err != nil {
- return nil, err
- }
- // Get the openapi object metadata
- s := visitor.resources.LookupResource(gvk)
- oapiKind, err := getKind(s)
- if err != nil {
- return nil, err
- }
- data := apply.NewRawElementData(recorded, local, remote)
- fieldName := ""
- item, err := visitor.getItem(oapiKind, fieldName, data)
- if err != nil {
- return nil, err
- }
- // Collate each field of the item into a combined Element
- return item.CreateElement(visitor)
- }
- // getItem returns the appropriate Item based on the underlying type of the arguments
- func (v *ElementBuildingVisitor) getItem(s proto.Schema, name string, data apply.RawElementData) (Item, error) {
- kind, err := getType(data.GetRecorded(), data.GetLocal(), data.GetRemote())
- if err != nil {
- return nil, err
- }
- if kind == nil {
- // All of the items values are nil.
- return &emptyItem{Name: name}, nil
- }
- // Create an item matching the type
- switch kind.Kind() {
- case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint,
- reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64,
- reflect.String:
- p, err := getPrimitive(s)
- if err != nil {
- return nil, fmt.Errorf("expected openapi Primitive, was %T for %v (%v)", s, kind, err)
- }
- return &primitiveItem{name, p, data}, nil
- case reflect.Array, reflect.Slice:
- a, err := getArray(s)
- if err != nil {
- return nil, fmt.Errorf("expected openapi Array, was %T for %v (%v)", s, kind, err)
- }
- return &listItem{
- Name: name,
- Array: a,
- ListElementData: apply.ListElementData{
- RawElementData: data,
- },
- }, nil
- case reflect.Map:
- if k, err := getKind(s); err == nil {
- return &typeItem{
- Name: name,
- Type: k,
- MapElementData: apply.MapElementData{
- RawElementData: data,
- },
- }, nil
- }
- // If it looks like a map, and no openapi type is found, default to mapItem
- m, err := getMap(s)
- if err != nil {
- return nil, fmt.Errorf("expected openapi Kind or Map, was %T for %v (%v)", s, kind, err)
- }
- return &mapItem{
- Name: name,
- Map: m,
- MapElementData: apply.MapElementData{
- RawElementData: data,
- },
- }, nil
- }
- return nil, fmt.Errorf("unsupported type %v", kind)
- }
|