mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			154 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2014 The Kubernetes Authors All rights reserved.
 | |
| 
 | |
| 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 conversion
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"path"
 | |
| 	"reflect"
 | |
| 
 | |
| 	"k8s.io/kubernetes/pkg/api/unversioned"
 | |
| )
 | |
| 
 | |
| // MetaFactory is used to store and retrieve the version and kind
 | |
| // information for all objects in a scheme.
 | |
| type MetaFactory interface {
 | |
| 	// Update sets the given version and kind onto the object.
 | |
| 	Update(version, kind string, obj interface{}) error
 | |
| 	// Interpret should return the group,version,kind of the wire-format of
 | |
| 	// the object.
 | |
| 	Interpret(data []byte) (gvk unversioned.GroupVersionKind, err error)
 | |
| }
 | |
| 
 | |
| // DefaultMetaFactory is a default factory for versioning objects in JSON. The object
 | |
| // in memory and in the default JSON serialization will use the "kind" and "apiVersion"
 | |
| // fields.
 | |
| var DefaultMetaFactory = SimpleMetaFactory{KindField: "Kind", VersionField: "APIVersion"}
 | |
| 
 | |
| // SimpleMetaFactory provides default methods for retrieving the type and version of objects
 | |
| // that are identified with an "apiVersion" and "kind" fields in their JSON
 | |
| // serialization. It may be parameterized with the names of the fields in memory, or an
 | |
| // optional list of base structs to search for those fields in memory.
 | |
| type SimpleMetaFactory struct {
 | |
| 	// The name of the API version field in memory of the struct
 | |
| 	VersionField string
 | |
| 	// The name of the kind field in memory of the struct.
 | |
| 	KindField string
 | |
| 	// Optional, if set will look in the named inline structs to find the fields to set.
 | |
| 	BaseFields []string
 | |
| }
 | |
| 
 | |
| // Interpret will return the group,version,kind of the JSON wire-format
 | |
| // encoding of an object, or an error.
 | |
| func (SimpleMetaFactory) Interpret(data []byte) (unversioned.GroupVersionKind, error) {
 | |
| 	findKind := struct {
 | |
| 		APIVersion string `json:"apiVersion,omitempty"`
 | |
| 		Kind       string `json:"kind,omitempty"`
 | |
| 	}{}
 | |
| 	err := json.Unmarshal(data, &findKind)
 | |
| 	if err != nil {
 | |
| 		return unversioned.GroupVersionKind{}, fmt.Errorf("couldn't get version/kind; json parse error: %v", err)
 | |
| 	}
 | |
| 	gv, err := unversioned.ParseGroupVersion(findKind.APIVersion)
 | |
| 	if err != nil {
 | |
| 		return unversioned.GroupVersionKind{}, fmt.Errorf("couldn't parse apiVersion: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	return gv.WithKind(findKind.Kind), nil
 | |
| }
 | |
| 
 | |
| func (f SimpleMetaFactory) Update(version, kind string, obj interface{}) error {
 | |
| 	return UpdateVersionAndKind(f.BaseFields, f.VersionField, version, f.KindField, kind, obj)
 | |
| }
 | |
| 
 | |
| // UpdateVersionAndKind uses reflection to find and set the versionField and kindField fields
 | |
| // on a pointer to a struct to version and kind. Provided as a convenience for others
 | |
| // implementing MetaFactory. Pass an array to baseFields to check one or more nested structs
 | |
| // for the named fields. The version field is treated as optional if it is not present in the struct.
 | |
| // TODO: this method is on its way out
 | |
| func UpdateVersionAndKind(baseFields []string, versionField, version, kindField, kind string, obj interface{}) error {
 | |
| 	if typed, ok := obj.(unversioned.ObjectKind); ok {
 | |
| 		if len(version) == 0 && len(kind) == 0 {
 | |
| 			typed.SetGroupVersionKind(nil)
 | |
| 		} else {
 | |
| 			gv, err := unversioned.ParseGroupVersion(version)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			typed.SetGroupVersionKind(&unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind})
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 	v, err := EnforcePtr(obj)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	pkg := path.Base(v.Type().PkgPath())
 | |
| 	t := v.Type()
 | |
| 	name := t.Name()
 | |
| 	if v.Kind() != reflect.Struct {
 | |
| 		return fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), name, v.Interface())
 | |
| 	}
 | |
| 
 | |
| 	for i := range baseFields {
 | |
| 		base := v.FieldByName(baseFields[i])
 | |
| 		if !base.IsValid() {
 | |
| 			continue
 | |
| 		}
 | |
| 		v = base
 | |
| 	}
 | |
| 
 | |
| 	field := v.FieldByName(kindField)
 | |
| 	if !field.IsValid() {
 | |
| 		// Types defined in the unversioned package are allowed to not have a
 | |
| 		// kindField. Clients will have to know what they are based on the
 | |
| 		// context.
 | |
| 		// TODO: add some type trait here, or some way of indicating whether
 | |
| 		// this feature is allowed on a per-type basis. Using package name is
 | |
| 		// overly broad and a bit hacky.
 | |
| 		if pkg == "unversioned" {
 | |
| 			return nil
 | |
| 		}
 | |
| 		return fmt.Errorf("couldn't find %v field in %#v", kindField, v.Interface())
 | |
| 	}
 | |
| 	field.SetString(kind)
 | |
| 
 | |
| 	if field := v.FieldByName(versionField); field.IsValid() {
 | |
| 		field.SetString(version)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // EnforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value
 | |
| // of the dereferenced pointer, ensuring that it is settable/addressable.
 | |
| // Returns an error if this is not possible.
 | |
| func EnforcePtr(obj interface{}) (reflect.Value, error) {
 | |
| 	v := reflect.ValueOf(obj)
 | |
| 	if v.Kind() != reflect.Ptr {
 | |
| 		if v.Kind() == reflect.Invalid {
 | |
| 			return reflect.Value{}, fmt.Errorf("expected pointer, but got invalid kind")
 | |
| 		}
 | |
| 		return reflect.Value{}, fmt.Errorf("expected pointer, but got %v type", v.Type())
 | |
| 	}
 | |
| 	if v.IsNil() {
 | |
| 		return reflect.Value{}, fmt.Errorf("expected pointer, but got nil")
 | |
| 	}
 | |
| 	return v.Elem(), nil
 | |
| }
 |