Update go dependencies and cleanup deprecated packages

This commit is contained in:
Manuel de Brito Fontes 2018-01-07 12:10:25 -03:00
parent 03a1e20fde
commit 44fd79d061
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1099 changed files with 75691 additions and 31913 deletions

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["swagger_doc_generator_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime",
library = ":go_default_library",
)
@ -18,6 +19,7 @@ go_library(
"codec.go",
"codec_check.go",
"conversion.go",
"converter.go",
"doc.go",
"embedded.go",
"error.go",
@ -33,12 +35,16 @@ go_library(
"types_proto.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime",
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion/queryparams:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
],
)
@ -46,20 +52,26 @@ go_test(
name = "go_default_xtest",
srcs = [
"conversion_test.go",
"converter_test.go",
"embedded_test.go",
"extension_test.go",
"scheme_test.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime_test",
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
],
)

View file

@ -139,6 +139,7 @@ func NewParameterCodec(scheme *Scheme) ParameterCodec {
typer: scheme,
convertor: scheme,
creator: scheme,
defaulter: scheme,
}
}
@ -147,6 +148,7 @@ type parameterCodec struct {
typer ObjectTyper
convertor ObjectConvertor
creator ObjectCreater
defaulter ObjectDefaulter
}
var _ ParameterCodec = &parameterCodec{}
@ -163,9 +165,17 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from schema.Gro
}
for i := range targetGVKs {
if targetGVKs[i].GroupVersion() == from {
return c.convertor.Convert(&parameters, into, nil)
if err := c.convertor.Convert(&parameters, into, nil); err != nil {
return err
}
// in the case where we going into the same object we're receiving, default on the outbound object
if c.defaulter != nil {
c.defaulter.Default(into)
}
return nil
}
}
input, err := c.creator.New(from.WithKind(targetGVKs[0].Kind))
if err != nil {
return err
@ -173,6 +183,10 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from schema.Gro
if err := c.convertor.Convert(&parameters, input, nil); err != nil {
return err
}
// if we have defaulter, default the input before converting to output
if c.defaulter != nil {
c.defaulter.Default(input)
}
return c.convertor.Convert(input, into, nil)
}

793
vendor/k8s.io/apimachinery/pkg/runtime/converter.go generated vendored Normal file
View file

@ -0,0 +1,793 @@
/*
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 runtime
import (
"bytes"
encodingjson "encoding/json"
"fmt"
"math"
"os"
"reflect"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/util/json"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"github.com/golang/glog"
)
// UnstructuredConverter is an interface for converting between interface{}
// and map[string]interface representation.
type UnstructuredConverter interface {
ToUnstructured(obj interface{}) (map[string]interface{}, error)
FromUnstructured(u map[string]interface{}, obj interface{}) error
}
type structField struct {
structType reflect.Type
field int
}
type fieldInfo struct {
name string
nameValue reflect.Value
omitempty bool
}
type fieldsCacheMap map[structField]*fieldInfo
type fieldsCache struct {
sync.Mutex
value atomic.Value
}
func newFieldsCache() *fieldsCache {
cache := &fieldsCache{}
cache.value.Store(make(fieldsCacheMap))
return cache
}
var (
marshalerType = reflect.TypeOf(new(encodingjson.Marshaler)).Elem()
unmarshalerType = reflect.TypeOf(new(encodingjson.Unmarshaler)).Elem()
mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
stringType = reflect.TypeOf(string(""))
int64Type = reflect.TypeOf(int64(0))
uint64Type = reflect.TypeOf(uint64(0))
float64Type = reflect.TypeOf(float64(0))
boolType = reflect.TypeOf(bool(false))
fieldCache = newFieldsCache()
// DefaultUnstructuredConverter performs unstructured to Go typed object conversions.
DefaultUnstructuredConverter = &unstructuredConverter{
mismatchDetection: parseBool(os.Getenv("KUBE_PATCH_CONVERSION_DETECTOR")),
comparison: conversion.EqualitiesOrDie(
func(a, b time.Time) bool {
return a.UTC() == b.UTC()
},
),
}
)
func parseBool(key string) bool {
if len(key) == 0 {
return false
}
value, err := strconv.ParseBool(key)
if err != nil {
utilruntime.HandleError(fmt.Errorf("Couldn't parse '%s' as bool for unstructured mismatch detection", key))
}
return value
}
// unstructuredConverter knows how to convert between interface{} and
// Unstructured in both ways.
type unstructuredConverter struct {
// If true, we will be additionally running conversion via json
// to ensure that the result is true.
// This is supposed to be set only in tests.
mismatchDetection bool
// comparison is the default test logic used to compare
comparison conversion.Equalities
}
// NewTestUnstructuredConverter creates an UnstructuredConverter that accepts JSON typed maps and translates them
// to Go types via reflection. It performs mismatch detection automatically and is intended for use by external
// test tools. Use DefaultUnstructuredConverter if you do not explicitly need mismatch detection.
func NewTestUnstructuredConverter(comparison conversion.Equalities) UnstructuredConverter {
return &unstructuredConverter{
mismatchDetection: true,
comparison: comparison,
}
}
// FromUnstructured converts an object from map[string]interface{} representation into a concrete type.
// It uses encoding/json/Unmarshaler if object implements it or reflection if not.
func (c *unstructuredConverter) FromUnstructured(u map[string]interface{}, obj interface{}) error {
t := reflect.TypeOf(obj)
value := reflect.ValueOf(obj)
if t.Kind() != reflect.Ptr || value.IsNil() {
return fmt.Errorf("FromUnstructured requires a non-nil pointer to an object, got %v", t)
}
err := fromUnstructured(reflect.ValueOf(u), value.Elem())
if c.mismatchDetection {
newObj := reflect.New(t.Elem()).Interface()
newErr := fromUnstructuredViaJSON(u, newObj)
if (err != nil) != (newErr != nil) {
glog.Fatalf("FromUnstructured unexpected error for %v: error: %v", u, err)
}
if err == nil && !c.comparison.DeepEqual(obj, newObj) {
glog.Fatalf("FromUnstructured mismatch\nobj1: %#v\nobj2: %#v", obj, newObj)
}
}
return err
}
func fromUnstructuredViaJSON(u map[string]interface{}, obj interface{}) error {
data, err := json.Marshal(u)
if err != nil {
return err
}
return json.Unmarshal(data, obj)
}
func fromUnstructured(sv, dv reflect.Value) error {
sv = unwrapInterface(sv)
if !sv.IsValid() {
dv.Set(reflect.Zero(dv.Type()))
return nil
}
st, dt := sv.Type(), dv.Type()
switch dt.Kind() {
case reflect.Map, reflect.Slice, reflect.Ptr, reflect.Struct, reflect.Interface:
// Those require non-trivial conversion.
default:
// This should handle all simple types.
if st.AssignableTo(dt) {
dv.Set(sv)
return nil
}
// We cannot simply use "ConvertibleTo", as JSON doesn't support conversions
// between those four groups: bools, integers, floats and string. We need to
// do the same.
if st.ConvertibleTo(dt) {
switch st.Kind() {
case reflect.String:
switch dt.Kind() {
case reflect.String:
dv.Set(sv.Convert(dt))
return nil
}
case reflect.Bool:
switch dt.Kind() {
case reflect.Bool:
dv.Set(sv.Convert(dt))
return nil
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
switch dt.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
dv.Set(sv.Convert(dt))
return nil
}
case reflect.Float32, reflect.Float64:
switch dt.Kind() {
case reflect.Float32, reflect.Float64:
dv.Set(sv.Convert(dt))
return nil
}
if sv.Float() == math.Trunc(sv.Float()) {
dv.Set(sv.Convert(dt))
return nil
}
}
return fmt.Errorf("cannot convert %s to %s", st.String(), dt.String())
}
}
// Check if the object has a custom JSON marshaller/unmarshaller.
if reflect.PtrTo(dt).Implements(unmarshalerType) {
data, err := json.Marshal(sv.Interface())
if err != nil {
return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
}
unmarshaler := dv.Addr().Interface().(encodingjson.Unmarshaler)
return unmarshaler.UnmarshalJSON(data)
}
switch dt.Kind() {
case reflect.Map:
return mapFromUnstructured(sv, dv)
case reflect.Slice:
return sliceFromUnstructured(sv, dv)
case reflect.Ptr:
return pointerFromUnstructured(sv, dv)
case reflect.Struct:
return structFromUnstructured(sv, dv)
case reflect.Interface:
return interfaceFromUnstructured(sv, dv)
default:
return fmt.Errorf("unrecognized type: %v", dt.Kind())
}
}
func fieldInfoFromField(structType reflect.Type, field int) *fieldInfo {
fieldCacheMap := fieldCache.value.Load().(fieldsCacheMap)
if info, ok := fieldCacheMap[structField{structType, field}]; ok {
return info
}
// Cache miss - we need to compute the field name.
info := &fieldInfo{}
typeField := structType.Field(field)
jsonTag := typeField.Tag.Get("json")
if len(jsonTag) == 0 {
// Make the first character lowercase.
if typeField.Name == "" {
info.name = typeField.Name
} else {
info.name = strings.ToLower(typeField.Name[:1]) + typeField.Name[1:]
}
} else {
items := strings.Split(jsonTag, ",")
info.name = items[0]
for i := range items {
if items[i] == "omitempty" {
info.omitempty = true
}
}
}
info.nameValue = reflect.ValueOf(info.name)
fieldCache.Lock()
defer fieldCache.Unlock()
fieldCacheMap = fieldCache.value.Load().(fieldsCacheMap)
newFieldCacheMap := make(fieldsCacheMap)
for k, v := range fieldCacheMap {
newFieldCacheMap[k] = v
}
newFieldCacheMap[structField{structType, field}] = info
fieldCache.value.Store(newFieldCacheMap)
return info
}
func unwrapInterface(v reflect.Value) reflect.Value {
for v.Kind() == reflect.Interface {
v = v.Elem()
}
return v
}
func mapFromUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if st.Kind() != reflect.Map {
return fmt.Errorf("cannot restore map from %v", st.Kind())
}
if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) {
return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key())
}
if sv.IsNil() {
dv.Set(reflect.Zero(dt))
return nil
}
dv.Set(reflect.MakeMap(dt))
for _, key := range sv.MapKeys() {
value := reflect.New(dt.Elem()).Elem()
if val := unwrapInterface(sv.MapIndex(key)); val.IsValid() {
if err := fromUnstructured(val, value); err != nil {
return err
}
} else {
value.Set(reflect.Zero(dt.Elem()))
}
if st.Key().AssignableTo(dt.Key()) {
dv.SetMapIndex(key, value)
} else {
dv.SetMapIndex(key.Convert(dt.Key()), value)
}
}
return nil
}
func sliceFromUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if st.Kind() == reflect.String && dt.Elem().Kind() == reflect.Uint8 {
// We store original []byte representation as string.
// This conversion is allowed, but we need to be careful about
// marshaling data appropriately.
if len(sv.Interface().(string)) > 0 {
marshalled, err := json.Marshal(sv.Interface())
if err != nil {
return fmt.Errorf("error encoding %s to json: %v", st, err)
}
// TODO: Is this Unmarshal needed?
var data []byte
err = json.Unmarshal(marshalled, &data)
if err != nil {
return fmt.Errorf("error decoding from json: %v", err)
}
dv.SetBytes(data)
} else {
dv.Set(reflect.Zero(dt))
}
return nil
}
if st.Kind() != reflect.Slice {
return fmt.Errorf("cannot restore slice from %v", st.Kind())
}
if sv.IsNil() {
dv.Set(reflect.Zero(dt))
return nil
}
dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
for i := 0; i < sv.Len(); i++ {
if err := fromUnstructured(sv.Index(i), dv.Index(i)); err != nil {
return err
}
}
return nil
}
func pointerFromUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if st.Kind() == reflect.Ptr && sv.IsNil() {
dv.Set(reflect.Zero(dt))
return nil
}
dv.Set(reflect.New(dt.Elem()))
switch st.Kind() {
case reflect.Ptr, reflect.Interface:
return fromUnstructured(sv.Elem(), dv.Elem())
default:
return fromUnstructured(sv, dv.Elem())
}
}
func structFromUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if st.Kind() != reflect.Map {
return fmt.Errorf("cannot restore struct from: %v", st.Kind())
}
for i := 0; i < dt.NumField(); i++ {
fieldInfo := fieldInfoFromField(dt, i)
fv := dv.Field(i)
if len(fieldInfo.name) == 0 {
// This field is inlined.
if err := fromUnstructured(sv, fv); err != nil {
return err
}
} else {
value := unwrapInterface(sv.MapIndex(fieldInfo.nameValue))
if value.IsValid() {
if err := fromUnstructured(value, fv); err != nil {
return err
}
} else {
fv.Set(reflect.Zero(fv.Type()))
}
}
}
return nil
}
func interfaceFromUnstructured(sv, dv reflect.Value) error {
// TODO: Is this conversion safe?
dv.Set(sv)
return nil
}
// ToUnstructured converts an object into map[string]interface{} representation.
// It uses encoding/json/Marshaler if object implements it or reflection if not.
func (c *unstructuredConverter) ToUnstructured(obj interface{}) (map[string]interface{}, error) {
var u map[string]interface{}
var err error
if unstr, ok := obj.(Unstructured); ok {
// UnstructuredContent() mutates the object so we need to make a copy first
u = unstr.DeepCopyObject().(Unstructured).UnstructuredContent()
} else {
t := reflect.TypeOf(obj)
value := reflect.ValueOf(obj)
if t.Kind() != reflect.Ptr || value.IsNil() {
return nil, fmt.Errorf("ToUnstructured requires a non-nil pointer to an object, got %v", t)
}
u = map[string]interface{}{}
err = toUnstructured(value.Elem(), reflect.ValueOf(&u).Elem())
}
if c.mismatchDetection {
newUnstr := map[string]interface{}{}
newErr := toUnstructuredViaJSON(obj, &newUnstr)
if (err != nil) != (newErr != nil) {
glog.Fatalf("ToUnstructured unexpected error for %v: error: %v; newErr: %v", obj, err, newErr)
}
if err == nil && !c.comparison.DeepEqual(u, newUnstr) {
glog.Fatalf("ToUnstructured mismatch\nobj1: %#v\nobj2: %#v", u, newUnstr)
}
}
if err != nil {
return nil, err
}
return u, nil
}
// DeepCopyJSON deep copies the passed value, assuming it is a valid JSON representation i.e. only contains
// types produced by json.Unmarshal().
func DeepCopyJSON(x map[string]interface{}) map[string]interface{} {
return DeepCopyJSONValue(x).(map[string]interface{})
}
// DeepCopyJSONValue deep copies the passed value, assuming it is a valid JSON representation i.e. only contains
// types produced by json.Unmarshal().
func DeepCopyJSONValue(x interface{}) interface{} {
switch x := x.(type) {
case map[string]interface{}:
clone := make(map[string]interface{}, len(x))
for k, v := range x {
clone[k] = DeepCopyJSONValue(v)
}
return clone
case []interface{}:
clone := make([]interface{}, len(x))
for i, v := range x {
clone[i] = DeepCopyJSONValue(v)
}
return clone
case string, int64, bool, float64, nil, encodingjson.Number:
return x
default:
panic(fmt.Errorf("cannot deep copy %T", x))
}
}
func toUnstructuredViaJSON(obj interface{}, u *map[string]interface{}) error {
data, err := json.Marshal(obj)
if err != nil {
return err
}
return json.Unmarshal(data, u)
}
var (
nullBytes = []byte("null")
trueBytes = []byte("true")
falseBytes = []byte("false")
)
func getMarshaler(v reflect.Value) (encodingjson.Marshaler, bool) {
// Check value receivers if v is not a pointer and pointer receivers if v is a pointer
if v.Type().Implements(marshalerType) {
return v.Interface().(encodingjson.Marshaler), true
}
// Check pointer receivers if v is not a pointer
if v.Kind() != reflect.Ptr && v.CanAddr() {
v = v.Addr()
if v.Type().Implements(marshalerType) {
return v.Interface().(encodingjson.Marshaler), true
}
}
return nil, false
}
func toUnstructured(sv, dv reflect.Value) error {
// Check if the object has a custom JSON marshaller/unmarshaller.
if marshaler, ok := getMarshaler(sv); ok {
if sv.Kind() == reflect.Ptr && sv.IsNil() {
// We're done - we don't need to store anything.
return nil
}
data, err := marshaler.MarshalJSON()
if err != nil {
return err
}
switch {
case len(data) == 0:
return fmt.Errorf("error decoding from json: empty value")
case bytes.Equal(data, nullBytes):
// We're done - we don't need to store anything.
case bytes.Equal(data, trueBytes):
dv.Set(reflect.ValueOf(true))
case bytes.Equal(data, falseBytes):
dv.Set(reflect.ValueOf(false))
case data[0] == '"':
var result string
err := json.Unmarshal(data, &result)
if err != nil {
return fmt.Errorf("error decoding string from json: %v", err)
}
dv.Set(reflect.ValueOf(result))
case data[0] == '{':
result := make(map[string]interface{})
err := json.Unmarshal(data, &result)
if err != nil {
return fmt.Errorf("error decoding object from json: %v", err)
}
dv.Set(reflect.ValueOf(result))
case data[0] == '[':
result := make([]interface{}, 0)
err := json.Unmarshal(data, &result)
if err != nil {
return fmt.Errorf("error decoding array from json: %v", err)
}
dv.Set(reflect.ValueOf(result))
default:
var (
resultInt int64
resultFloat float64
err error
)
if err = json.Unmarshal(data, &resultInt); err == nil {
dv.Set(reflect.ValueOf(resultInt))
} else if err = json.Unmarshal(data, &resultFloat); err == nil {
dv.Set(reflect.ValueOf(resultFloat))
} else {
return fmt.Errorf("error decoding number from json: %v", err)
}
}
return nil
}
st, dt := sv.Type(), dv.Type()
switch st.Kind() {
case reflect.String:
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.New(stringType))
}
dv.Set(reflect.ValueOf(sv.String()))
return nil
case reflect.Bool:
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.New(boolType))
}
dv.Set(reflect.ValueOf(sv.Bool()))
return nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.New(int64Type))
}
dv.Set(reflect.ValueOf(sv.Int()))
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.New(uint64Type))
}
dv.Set(reflect.ValueOf(sv.Uint()))
return nil
case reflect.Float32, reflect.Float64:
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.New(float64Type))
}
dv.Set(reflect.ValueOf(sv.Float()))
return nil
case reflect.Map:
return mapToUnstructured(sv, dv)
case reflect.Slice:
return sliceToUnstructured(sv, dv)
case reflect.Ptr:
return pointerToUnstructured(sv, dv)
case reflect.Struct:
return structToUnstructured(sv, dv)
case reflect.Interface:
return interfaceToUnstructured(sv, dv)
default:
return fmt.Errorf("unrecognized type: %v", st.Kind())
}
}
func mapToUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if sv.IsNil() {
dv.Set(reflect.Zero(dt))
return nil
}
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
if st.Key().Kind() == reflect.String {
switch st.Elem().Kind() {
// TODO It should be possible to reuse the slice for primitive types.
// However, it is panicing in the following form.
// case reflect.String, reflect.Bool,
// reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// sv.Set(sv)
// return nil
default:
// We need to do a proper conversion.
}
}
dv.Set(reflect.MakeMap(mapStringInterfaceType))
dv = dv.Elem()
dt = dv.Type()
}
if dt.Kind() != reflect.Map {
return fmt.Errorf("cannot convert struct to: %v", dt.Kind())
}
if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) {
return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key())
}
for _, key := range sv.MapKeys() {
value := reflect.New(dt.Elem()).Elem()
if err := toUnstructured(sv.MapIndex(key), value); err != nil {
return err
}
if st.Key().AssignableTo(dt.Key()) {
dv.SetMapIndex(key, value)
} else {
dv.SetMapIndex(key.Convert(dt.Key()), value)
}
}
return nil
}
func sliceToUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if sv.IsNil() {
dv.Set(reflect.Zero(dt))
return nil
}
if st.Elem().Kind() == reflect.Uint8 {
dv.Set(reflect.New(stringType))
data, err := json.Marshal(sv.Bytes())
if err != nil {
return err
}
var result string
if err = json.Unmarshal(data, &result); err != nil {
return err
}
dv.Set(reflect.ValueOf(result))
return nil
}
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
switch st.Elem().Kind() {
// TODO It should be possible to reuse the slice for primitive types.
// However, it is panicing in the following form.
// case reflect.String, reflect.Bool,
// reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// sv.Set(sv)
// return nil
default:
// We need to do a proper conversion.
dv.Set(reflect.MakeSlice(reflect.SliceOf(dt), sv.Len(), sv.Cap()))
dv = dv.Elem()
dt = dv.Type()
}
}
if dt.Kind() != reflect.Slice {
return fmt.Errorf("cannot convert slice to: %v", dt.Kind())
}
for i := 0; i < sv.Len(); i++ {
if err := toUnstructured(sv.Index(i), dv.Index(i)); err != nil {
return err
}
}
return nil
}
func pointerToUnstructured(sv, dv reflect.Value) error {
if sv.IsNil() {
// We're done - we don't need to store anything.
return nil
}
return toUnstructured(sv.Elem(), dv)
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Map, reflect.Slice:
// TODO: It seems that 0-len maps are ignored in it.
return v.IsNil() || v.Len() == 0
case reflect.Ptr, reflect.Interface:
return v.IsNil()
}
return false
}
func structToUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type()
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.MakeMap(mapStringInterfaceType))
dv = dv.Elem()
dt = dv.Type()
}
if dt.Kind() != reflect.Map {
return fmt.Errorf("cannot convert struct to: %v", dt.Kind())
}
realMap := dv.Interface().(map[string]interface{})
for i := 0; i < st.NumField(); i++ {
fieldInfo := fieldInfoFromField(st, i)
fv := sv.Field(i)
if fieldInfo.name == "-" {
// This field should be skipped.
continue
}
if fieldInfo.omitempty && isZero(fv) {
// omitempty fields should be ignored.
continue
}
if len(fieldInfo.name) == 0 {
// This field is inlined.
if err := toUnstructured(fv, dv); err != nil {
return err
}
continue
}
switch fv.Type().Kind() {
case reflect.String:
realMap[fieldInfo.name] = fv.String()
case reflect.Bool:
realMap[fieldInfo.name] = fv.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
realMap[fieldInfo.name] = fv.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
realMap[fieldInfo.name] = fv.Uint()
case reflect.Float32, reflect.Float64:
realMap[fieldInfo.name] = fv.Float()
default:
subv := reflect.New(dt.Elem()).Elem()
if err := toUnstructured(fv, subv); err != nil {
return err
}
dv.SetMapIndex(fieldInfo.nameValue, subv)
}
}
return nil
}
func interfaceToUnstructured(sv, dv reflect.Value) error {
if !sv.IsValid() || sv.IsNil() {
dv.Set(reflect.Zero(dv.Type()))
return nil
}
return toUnstructured(sv.Elem(), dv)
}

View file

@ -0,0 +1,597 @@
/*
Copyright 2015 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.
*/
// These tests are in a separate package to break cyclic dependency in tests.
// Unstructured type depends on unstructured converter package but we want to test how the converter handles
// the Unstructured type so we need to import both.
package runtime_test
import (
encodingjson "encoding/json"
"fmt"
"reflect"
"strconv"
"testing"
"time"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/json"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var simpleEquality = conversion.EqualitiesOrDie(
func(a, b time.Time) bool {
return a.UTC() == b.UTC()
},
)
// Definte a number of test types.
type A struct {
A int `json:"aa,omitempty"`
B string `json:"ab,omitempty"`
C bool `json:"ac,omitempty"`
}
type B struct {
A A `json:"ba"`
B string `json:"bb"`
C map[string]string `json:"bc"`
D []string `json:"bd"`
}
type C struct {
A []A `json:"ca"`
B `json:",inline"`
C string `json:"cc"`
D *int64 `json:"cd"`
E map[string]int `json:"ce"`
F []bool `json:"cf"`
G []int `json:"cg"`
H float32 `json:"ch"`
I []interface{} `json:"ci"`
}
type D struct {
A []interface{} `json:"da"`
}
type E struct {
A interface{} `json:"ea"`
}
type F struct {
A string `json:"fa"`
B map[string]string `json:"fb"`
C []A `json:"fc"`
D int `json:"fd"`
E float32 `json:"fe"`
F []string `json:"ff"`
G []int `json:"fg"`
H []bool `json:"fh"`
I []float32 `json:"fi"`
}
type G struct {
CustomValue1 CustomValue `json:"customValue1"`
CustomValue2 *CustomValue `json:"customValue2"`
CustomPointer1 CustomPointer `json:"customPointer1"`
CustomPointer2 *CustomPointer `json:"customPointer2"`
}
type CustomValue struct {
data []byte
}
// MarshalJSON has a value receiver on this type.
func (c CustomValue) MarshalJSON() ([]byte, error) {
return c.data, nil
}
type CustomPointer struct {
data []byte
}
// MarshalJSON has a pointer receiver on this type.
func (c *CustomPointer) MarshalJSON() ([]byte, error) {
return c.data, nil
}
func doRoundTrip(t *testing.T, item interface{}) {
data, err := json.Marshal(item)
if err != nil {
t.Errorf("Error when marshaling object: %v", err)
return
}
unstr := make(map[string]interface{})
err = json.Unmarshal(data, &unstr)
if err != nil {
t.Errorf("Error when unmarshaling to unstructured: %v", err)
return
}
data, err = json.Marshal(unstr)
if err != nil {
t.Errorf("Error when marshaling unstructured: %v", err)
return
}
unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
err = json.Unmarshal(data, unmarshalledObj)
if err != nil {
t.Errorf("Error when unmarshaling to object: %v", err)
return
}
if !reflect.DeepEqual(item, unmarshalledObj) {
t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj))
return
}
// TODO: should be using mismatch detection but fails due to another error
newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(item)
if err != nil {
t.Errorf("ToUnstructured failed: %v", err)
return
}
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
err = runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(newUnstr, newObj)
if err != nil {
t.Errorf("FromUnstructured failed: %v", err)
return
}
if !reflect.DeepEqual(item, newObj) {
t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj))
}
}
func TestRoundTrip(t *testing.T) {
intVal := int64(42)
testCases := []struct {
obj interface{}
}{
{
obj: &unstructured.UnstructuredList{
Object: map[string]interface{}{
"kind": "List",
},
// Not testing a list with nil Items because items is a non-optional field and hence
// is always marshaled into an empty array which is not equal to nil when unmarshalled and will fail.
// That is expected.
Items: []unstructured.Unstructured{},
},
},
{
obj: &unstructured.UnstructuredList{
Object: map[string]interface{}{
"kind": "List",
},
Items: []unstructured.Unstructured{
{
Object: map[string]interface{}{
"kind": "Pod",
},
},
},
},
},
{
obj: &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "Pod",
},
},
},
{
obj: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Foo",
"metadata": map[string]interface{}{
"name": "foo1",
},
},
},
},
{
// This (among others) tests nil map, slice and pointer.
obj: &C{
C: "ccc",
},
},
{
// This (among others) tests empty map and slice.
obj: &C{
A: []A{},
C: "ccc",
E: map[string]int{},
I: []interface{}{},
},
},
{
obj: &C{
A: []A{
{
A: 1,
B: "11",
C: true,
},
{
A: 2,
B: "22",
C: false,
},
},
B: B{
A: A{
A: 3,
B: "33",
},
B: "bbb",
C: map[string]string{
"k1": "v1",
"k2": "v2",
},
D: []string{"s1", "s2"},
},
C: "ccc",
D: &intVal,
E: map[string]int{
"k1": 1,
"k2": 2,
},
F: []bool{true, false, false},
G: []int{1, 2, 5},
H: 3.3,
I: []interface{}{nil, nil, nil},
},
},
{
// Test slice of interface{} with empty slices.
obj: &D{
A: []interface{}{[]interface{}{}, []interface{}{}},
},
},
{
// Test slice of interface{} with different values.
obj: &D{
A: []interface{}{3.0, "3.0", nil},
},
},
}
for i := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
doRoundTrip(t, testCases[i].obj)
})
}
}
// Verifies that:
// 1) serialized json -> object
// 2) serialized json -> map[string]interface{} -> object
// produces the same object.
func doUnrecognized(t *testing.T, jsonData string, item interface{}, expectedErr error) {
unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
err := json.Unmarshal([]byte(jsonData), unmarshalledObj)
if (err != nil) != (expectedErr != nil) {
t.Errorf("Unexpected error when unmarshaling to object: %v, expected: %v", err, expectedErr)
return
}
unstr := make(map[string]interface{})
err = json.Unmarshal([]byte(jsonData), &unstr)
if err != nil {
t.Errorf("Error when unmarshaling to unstructured: %v", err)
return
}
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
err = runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(unstr, newObj)
if (err != nil) != (expectedErr != nil) {
t.Errorf("Unexpected error in FromUnstructured: %v, expected: %v", err, expectedErr)
}
if expectedErr == nil && !reflect.DeepEqual(unmarshalledObj, newObj) {
t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(unmarshalledObj, newObj))
}
}
func TestUnrecognized(t *testing.T) {
testCases := []struct {
data string
obj interface{}
err error
}{
{
data: "{\"da\":[3.0,\"3.0\",null]}",
obj: &D{},
},
{
data: "{\"ea\":[3.0,\"3.0\",null]}",
obj: &E{},
},
{
data: "{\"ea\":[null,null,null]}",
obj: &E{},
},
{
data: "{\"ea\":[[],[null]]}",
obj: &E{},
},
{
data: "{\"ea\":{\"a\":[],\"b\":null}}",
obj: &E{},
},
{
data: "{\"fa\":\"fa\",\"fb\":{\"a\":\"a\"}}",
obj: &F{},
},
{
data: "{\"fa\":\"fa\",\"fb\":{\"a\":null}}",
obj: &F{},
},
{
data: "{\"fc\":[null]}",
obj: &F{},
},
{
data: "{\"fc\":[{\"aa\":123,\"ab\":\"bbb\"}]}",
obj: &F{},
},
{
// Only unknown fields
data: "{\"fx\":[{\"aa\":123,\"ab\":\"bbb\"}],\"fz\":123}",
obj: &F{},
},
{
data: "{\"fc\":[{\"aa\":\"aaa\",\"ab\":\"bbb\"}]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"),
},
{
data: "{\"fd\":123,\"fe\":3.5}",
obj: &F{},
},
{
data: "{\"ff\":[\"abc\"],\"fg\":[123],\"fh\":[true,false]}",
obj: &F{},
},
{
// Invalid string data
data: "{\"fa\":123}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
},
{
// Invalid string data
data: "{\"fa\":13.5}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
},
{
// Invalid string data
data: "{\"fa\":true}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal bool into Go value of type string"),
},
{
// Invalid []string data
data: "{\"ff\":123}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"),
},
{
// Invalid []string data
data: "{\"ff\":3.5}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"),
},
{
// Invalid []string data
data: "{\"ff\":[123,345]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
},
{
// Invalid []int data
data: "{\"fg\":123}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []int"),
},
{
// Invalid []int data
data: "{\"fg\":\"abc\"}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []int"),
},
{
// Invalid []int data
data: "{\"fg\":[\"abc\"]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"),
},
{
// Invalid []int data
data: "{\"fg\":[3.5]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"),
},
{
// Invalid []int data
data: "{\"fg\":[true,false]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"),
},
{
// Invalid []bool data
data: "{\"fh\":123}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []bool"),
},
{
// Invalid []bool data
data: "{\"fh\":\"abc\"}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []bool"),
},
{
// Invalid []bool data
data: "{\"fh\":[\"abc\"]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type bool"),
},
{
// Invalid []bool data
data: "{\"fh\":[3.5]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"),
},
{
// Invalid []bool data
data: "{\"fh\":[123]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"),
},
{
// Invalid []float data
data: "{\"fi\":123}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []float32"),
},
{
// Invalid []float data
data: "{\"fi\":\"abc\"}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []float32"),
},
{
// Invalid []float data
data: "{\"fi\":[\"abc\"]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal string into Go value of type float32"),
},
{
// Invalid []float data
data: "{\"fi\":[true]}",
obj: &F{},
err: fmt.Errorf("json: cannot unmarshal bool into Go value of type float32"),
},
}
for _, tc := range testCases {
t.Run(tc.data, func(t *testing.T) {
doUnrecognized(t, tc.data, tc.obj, tc.err)
})
}
}
func TestDeepCopyJSON(t *testing.T) {
src := map[string]interface{}{
"a": nil,
"b": int64(123),
"c": map[string]interface{}{
"a": "b",
},
"d": []interface{}{
int64(1), int64(2),
},
"e": "estr",
"f": true,
"g": encodingjson.Number("123"),
}
deepCopy := runtime.DeepCopyJSON(src)
assert.Equal(t, src, deepCopy)
}
func TestFloatIntConversion(t *testing.T) {
unstr := map[string]interface{}{"fd": float64(3)}
var obj F
if err := runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(unstr, &obj); err != nil {
t.Errorf("Unexpected error in FromUnstructured: %v", err)
}
data, err := json.Marshal(unstr)
if err != nil {
t.Fatalf("Error when marshaling unstructured: %v", err)
}
var unmarshalled F
if err := json.Unmarshal(data, &unmarshalled); err != nil {
t.Fatalf("Error when unmarshaling to object: %v", err)
}
if !reflect.DeepEqual(obj, unmarshalled) {
t.Errorf("Incorrect conversion, diff: %v", diff.ObjectReflectDiff(obj, unmarshalled))
}
}
func TestCustomToUnstructured(t *testing.T) {
testcases := []struct {
Data string
Expected interface{}
}{
{Data: `null`, Expected: nil},
{Data: `true`, Expected: true},
{Data: `false`, Expected: false},
{Data: `[]`, Expected: []interface{}{}},
{Data: `[1]`, Expected: []interface{}{int64(1)}},
{Data: `{}`, Expected: map[string]interface{}{}},
{Data: `{"a":1}`, Expected: map[string]interface{}{"a": int64(1)}},
{Data: `0`, Expected: int64(0)},
{Data: `0.0`, Expected: float64(0)},
}
for _, tc := range testcases {
tc := tc
t.Run(tc.Data, func(t *testing.T) {
t.Parallel()
result, err := runtime.NewTestUnstructuredConverter(simpleEquality).ToUnstructured(&G{
CustomValue1: CustomValue{data: []byte(tc.Data)},
CustomValue2: &CustomValue{data: []byte(tc.Data)},
CustomPointer1: CustomPointer{data: []byte(tc.Data)},
CustomPointer2: &CustomPointer{data: []byte(tc.Data)},
})
require.NoError(t, err)
for field, fieldResult := range result {
assert.Equal(t, tc.Expected, fieldResult, field)
}
})
}
}
func TestCustomToUnstructuredTopLevel(t *testing.T) {
// Only objects are supported at the top level
topLevelCases := []interface{}{
&CustomValue{data: []byte(`{"a":1}`)},
&CustomPointer{data: []byte(`{"a":1}`)},
}
expected := map[string]interface{}{"a": int64(1)}
for i, obj := range topLevelCases {
obj := obj
t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
result, err := runtime.NewTestUnstructuredConverter(simpleEquality).ToUnstructured(obj)
require.NoError(t, err)
assert.Equal(t, expected, result)
})
}
}

View file

@ -94,8 +94,6 @@ type missingVersionErr struct {
data string
}
// IsMissingVersion returns true if the error indicates that the provided object
// is missing a 'Version' field.
func NewMissingVersionErr(data string) error {
return &missingVersionErr{data}
}
@ -104,6 +102,8 @@ func (k *missingVersionErr) Error() string {
return fmt.Sprintf("Object 'apiVersion' is missing in '%s'", k.data)
}
// IsMissingVersion returns true if the error indicates that the provided object
// is missing a 'Version' field.
func IsMissingVersion(err error) bool {
if err == nil {
return false

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2018 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.

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2018 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.

View file

@ -203,13 +203,6 @@ type ObjectCreater interface {
New(kind schema.GroupVersionKind) (out Object, err error)
}
// ObjectCopier duplicates an object.
type ObjectCopier interface {
// Copy returns an exact copy of the provided Object, or an error if the
// copy could not be completed.
Copy(Object) (Object, error)
}
// ResourceVersioner provides methods for setting and retrieving
// the resource version from an API object.
type ResourceVersioner interface {
@ -240,13 +233,13 @@ type Object interface {
// Unstructured objects store values as map[string]interface{}, with only values that can be serialized
// to JSON allowed.
type Unstructured interface {
// IsUnstructuredObject is a marker interface to allow objects that can be serialized but not introspected
// to bypass conversion.
IsUnstructuredObject()
Object
// UnstructuredContent returns a non-nil, mutable map of the contents of this object. Values may be
// []interface{}, map[string]interface{}, or any primitive type. Contents are typically serialized to
// and from JSON.
UnstructuredContent() map[string]interface{}
// SetUnstructuredContent updates the object content to match the provided map.
SetUnstructuredContent(map[string]interface{})
// IsList returns true if this type is a list or matches the list convention - has an array called "items".
IsList() bool
// EachListItem should pass a single item out of the list as an Object to the provided function. Any

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["group_version_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/schema",
library = ":go_default_library",
)
@ -19,6 +20,7 @@ go_library(
"group_version.go",
"interfaces.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime/schema",
deps = ["//vendor/github.com/gogo/protobuf/proto:go_default_library"],
)

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2018 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.

View file

@ -1,5 +1,5 @@
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2018 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.

View file

@ -68,10 +68,6 @@ type Scheme struct {
// converter stores all registered conversion functions. It also has
// default coverting behavior.
converter *conversion.Converter
// cloner stores all registered copy functions. It also has default
// deep copy behavior.
cloner *conversion.Cloner
}
// Function to convert a field selector to internal representation.
@ -80,11 +76,10 @@ type FieldLabelConversionFunc func(label, value string) (internalLabel, internal
// NewScheme creates a new Scheme. This scheme is pluggable by default.
func NewScheme() *Scheme {
s := &Scheme{
gvkToType: map[schema.GroupVersionKind]reflect.Type{},
typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
unversionedKinds: map[string]reflect.Type{},
cloner: conversion.NewCloner(),
gvkToType: map[schema.GroupVersionKind]reflect.Type{},
typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
unversionedKinds: map[string]reflect.Type{},
fieldLabelConversionFuncs: map[string]map[string]FieldLabelConversionFunc{},
defaulterFuncs: map[reflect.Type]func(interface{}){},
}
@ -222,19 +217,22 @@ func (s *Scheme) AllKnownTypes() map[schema.GroupVersionKind]reflect.Type {
return s.gvkToType
}
// ObjectKind returns the group,version,kind of the go object and true if this object
// is considered unversioned, or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKind(obj Object) (schema.GroupVersionKind, bool, error) {
gvks, unversionedType, err := s.ObjectKinds(obj)
if err != nil {
return schema.GroupVersionKind{}, false, err
}
return gvks[0], unversionedType, nil
}
// ObjectKinds returns all possible group,version,kind of the go object, true if the
// object is considered unversioned, or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error) {
// Unstructured objects are always considered to have their declared GVK
if _, ok := obj.(Unstructured); ok {
// we require that the GVK be populated in order to recognize the object
gvk := obj.GetObjectKind().GroupVersionKind()
if len(gvk.Kind) == 0 {
return nil, false, NewMissingKindErr("unstructured object has no kind")
}
if len(gvk.Version) == 0 {
return nil, false, NewMissingVersionErr("unstructured object has no version")
}
return []schema.GroupVersionKind{gvk}, false, nil
}
v, err := conversion.EnforcePtr(obj)
if err != nil {
return nil, false, err
@ -343,7 +341,7 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
return nil
}
// Similar to AddConversionFuncs, but registers conversion functions that were
// AddGeneratedConversionFuncs registers conversion functions that were
// automatically generated.
func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error {
for _, f := range conversionFuncs {
@ -354,29 +352,6 @@ func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) err
return nil
}
// AddDeepCopyFuncs adds a function to the list of deep-copy functions.
// For the expected format of deep-copy function, see the comment for
// Copier.RegisterDeepCopyFunction.
func (s *Scheme) AddDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
for _, f := range deepCopyFuncs {
if err := s.cloner.RegisterDeepCopyFunc(f); err != nil {
return err
}
}
return nil
}
// Similar to AddDeepCopyFuncs, but registers deep-copy functions that were
// automatically generated.
func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...conversion.GeneratedDeepCopyFunc) error {
for _, fn := range deepCopyFuncs {
if err := s.cloner.RegisterGeneratedDeepCopyFunc(fn); err != nil {
return err
}
}
return nil
}
// AddFieldLabelConversionFunc adds a conversion function to convert field selectors
// of the given kind from the given version to internal version representation.
func (s *Scheme) AddFieldLabelConversionFunc(version, kind string, conversionFunc FieldLabelConversionFunc) error {
@ -420,28 +395,72 @@ func (s *Scheme) Default(src Object) {
}
}
// Copy does a deep copy of an API object.
func (s *Scheme) Copy(src Object) (Object, error) {
dst, err := s.DeepCopy(src)
if err != nil {
return nil, err
}
return dst.(Object), nil
}
// Performs a deep copy of the given object.
func (s *Scheme) DeepCopy(src interface{}) (interface{}, error) {
return s.cloner.DeepCopy(src)
}
// Convert will attempt to convert in into out. Both must be pointers. For easy
// testing of conversion functions. Returns an error if the conversion isn't
// possible. You can call this with types that haven't been registered (for example,
// a to test conversion of types that are nested within registered types). The
// context interface is passed to the convertor.
// TODO: identify whether context should be hidden, or behind a formal context/scope
// interface
// context interface is passed to the convertor. Convert also supports Unstructured
// types and will convert them intelligently.
func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
unstructuredIn, okIn := in.(Unstructured)
unstructuredOut, okOut := out.(Unstructured)
switch {
case okIn && okOut:
// converting unstructured input to an unstructured output is a straight copy - unstructured
// is a "smart holder" and the contents are passed by reference between the two objects
unstructuredOut.SetUnstructuredContent(unstructuredIn.UnstructuredContent())
return nil
case okOut:
// if the output is an unstructured object, use the standard Go type to unstructured
// conversion. The object must not be internal.
obj, ok := in.(Object)
if !ok {
return fmt.Errorf("unable to convert object type %T to Unstructured, must be a runtime.Object", in)
}
gvks, unversioned, err := s.ObjectKinds(obj)
if err != nil {
return err
}
gvk := gvks[0]
// if no conversion is necessary, convert immediately
if unversioned || gvk.Version != APIVersionInternal {
content, err := DefaultUnstructuredConverter.ToUnstructured(in)
if err != nil {
return err
}
unstructuredOut.SetUnstructuredContent(content)
return nil
}
// attempt to convert the object to an external version first.
target, ok := context.(GroupVersioner)
if !ok {
return fmt.Errorf("unable to convert the internal object type %T to Unstructured without providing a preferred version to convert to", in)
}
// Convert is implicitly unsafe, so we don't need to perform a safe conversion
versioned, err := s.UnsafeConvertToVersion(obj, target)
if err != nil {
return err
}
content, err := DefaultUnstructuredConverter.ToUnstructured(versioned)
if err != nil {
return err
}
unstructuredOut.SetUnstructuredContent(content)
return nil
case okIn:
// converting an unstructured object to any type is modeled by first converting
// the input to a versioned type, then running standard conversions
typed, err := s.unstructuredToTyped(unstructuredIn)
if err != nil {
return err
}
in = typed
}
flags, meta := s.generateConvertMeta(in)
meta.Context = context
if flags == 0 {
@ -450,8 +469,8 @@ func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
return s.converter.Convert(in, out, flags, meta)
}
// Converts the given field label and value for an kind field selector from
// versioned representation to an unversioned one.
// ConvertFieldLabel alters the given field label and value for an kind field selector from
// versioned representation to an unversioned one or returns an error.
func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
if s.fieldLabelConversionFuncs[version] == nil {
return DefaultMetaV1FieldSelectorConversion(label, value)
@ -481,15 +500,30 @@ func (s *Scheme) UnsafeConvertToVersion(in Object, target GroupVersioner) (Objec
// convertToVersion handles conversion with an optional copy.
func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (Object, error) {
// determine the incoming kinds with as few allocations as possible.
t := reflect.TypeOf(in)
if t.Kind() != reflect.Ptr {
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
}
t = t.Elem()
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
var t reflect.Type
if u, ok := in.(Unstructured); ok {
typed, err := s.unstructuredToTyped(u)
if err != nil {
return nil, err
}
in = typed
// unstructuredToTyped returns an Object, which must be a pointer to a struct.
t = reflect.TypeOf(in).Elem()
} else {
// determine the incoming kinds with as few allocations as possible.
t = reflect.TypeOf(in)
if t.Kind() != reflect.Ptr {
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
}
t = t.Elem()
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
}
}
kinds, ok := s.typeToGVK[t]
if !ok || len(kinds) == 0 {
return nil, NewNotRegisteredErrForType(t)
@ -501,27 +535,26 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
// TODO: when we move to server API versions, we should completely remove the unversioned concept
if unversionedKind, ok := s.unversionedTypes[t]; ok {
if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
return copyAndSetTargetKind(copy, s, in, gvk)
return copyAndSetTargetKind(copy, in, gvk)
}
return copyAndSetTargetKind(copy, s, in, unversionedKind)
return copyAndSetTargetKind(copy, in, unversionedKind)
}
return nil, NewNotRegisteredErrForTarget(t, target)
}
// target wants to use the existing type, set kind and return (no conversion necessary)
for _, kind := range kinds {
if gvk == kind {
return copyAndSetTargetKind(copy, s, in, gvk)
return copyAndSetTargetKind(copy, in, gvk)
}
}
// type is unversioned, no conversion necessary
if unversionedKind, ok := s.unversionedTypes[t]; ok {
if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
return copyAndSetTargetKind(copy, s, in, gvk)
return copyAndSetTargetKind(copy, in, gvk)
}
return copyAndSetTargetKind(copy, s, in, unversionedKind)
return copyAndSetTargetKind(copy, in, unversionedKind)
}
out, err := s.New(gvk)
@ -543,13 +576,32 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (
return out, nil
}
// unstructuredToTyped attempts to transform an unstructured object to a typed
// object if possible. It will return an error if conversion is not possible, or the versioned
// Go form of the object. Note that this conversion will lose fields.
func (s *Scheme) unstructuredToTyped(in Unstructured) (Object, error) {
// the type must be something we recognize
gvks, _, err := s.ObjectKinds(in)
if err != nil {
return nil, err
}
typed, err := s.New(gvks[0])
if err != nil {
return nil, err
}
if err := DefaultUnstructuredConverter.FromUnstructured(in.UnstructuredContent(), typed); err != nil {
return nil, fmt.Errorf("unable to convert unstructured object to %v: %v", gvks[0], err)
}
return typed, nil
}
// generateConvertMeta constructs the meta value we pass to Convert.
func (s *Scheme) generateConvertMeta(in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
return s.converter.DefaultMeta(reflect.TypeOf(in))
}
// copyAndSetTargetKind performs a conditional copy before returning the object, or an error if copy was not successful.
func copyAndSetTargetKind(copy bool, copier ObjectCopier, obj Object, kind schema.GroupVersionKind) (Object, error) {
func copyAndSetTargetKind(copy bool, obj Object, kind schema.GroupVersionKind) (Object, error) {
if copy {
obj = obj.DeepCopyObject()
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package runtime_test
import (
"fmt"
"reflect"
"strings"
"testing"
@ -126,14 +127,84 @@ func TestScheme(t *testing.T) {
t.Errorf("Expected %v, got %v", e, a)
}
// Test convert internal to unstructured
unstructuredObj := &runtimetesting.Unstructured{}
err = scheme.Convert(simple, unstructuredObj, nil)
if err == nil || !strings.Contains(err.Error(), "to Unstructured without providing a preferred version to convert to") {
t.Fatalf("Unexpected non-error: %v", err)
}
err = scheme.Convert(simple, unstructuredObj, schema.GroupVersion{Group: "test.group", Version: "testExternal"})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
if gvks, unversioned, err := scheme.ObjectKinds(unstructuredObj); err != nil || !reflect.DeepEqual(gvks[0], schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) || unversioned {
t.Errorf("Scheme did not recognize unversioned: %v, %#v %t", err, gvks, unversioned)
}
// Test convert external to unstructured
unstructuredObj = &runtimetesting.Unstructured{}
err = scheme.Convert(external, unstructuredObj, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e := unstructuredObj.GetObjectKind().GroupVersionKind(); !reflect.DeepEqual(e, schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
t.Errorf("Unexpected object kind: %#v", e)
}
// Test convert unstructured to unstructured
uIn := &runtimetesting.Unstructured{Object: map[string]interface{}{
"test": []interface{}{"other", "test"},
}}
uOut := &runtimetesting.Unstructured{}
err = scheme.Convert(uIn, uOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(uIn.Object, uOut.Object) {
t.Errorf("Unexpected object contents: %#v", uOut.Object)
}
// Test convert unstructured to structured
externalOut := &runtimetesting.ExternalSimple{}
err = scheme.Convert(unstructuredObj, externalOut, nil)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(external, externalOut) {
t.Errorf("Unexpected object contents: %#v", externalOut)
}
// Encode and Convert should each have caused an increment.
if e, a := 2, internalToExternalCalls; e != a {
if e, a := 3, internalToExternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// DecodeInto and Decode should each have caused an increment because of a conversion
if e, a := 2, externalToInternalCalls; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
// Verify that unstructured types must have V and K set
emptyObj := &runtimetesting.Unstructured{Object: make(map[string]interface{})}
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingKind(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test"})
if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingVersion(err) {
t.Errorf("unexpected error: %v", err)
}
emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test", Version: "v1"})
if _, _, err := scheme.ObjectKinds(emptyObj); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
func TestBadJSONRejection(t *testing.T) {
@ -367,6 +438,7 @@ func GetTestScheme() *runtime.Scheme {
internalGV := schema.GroupVersion{Version: "__internal"}
externalGV := schema.GroupVersion{Version: "v1"}
alternateExternalGV := schema.GroupVersion{Group: "custom", Version: "v1"}
alternateInternalGV := schema.GroupVersion{Group: "custom", Version: "__internal"}
differentExternalGV := schema.GroupVersion{Group: "other", Version: "v2"}
s := runtime.NewScheme()
@ -380,10 +452,15 @@ func GetTestScheme() *runtime.Scheme {
s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &runtimetesting.TestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &runtimetesting.ExternalTestType1{})
s.AddKnownTypeWithName(alternateInternalGV.WithKind("TestType3"), &runtimetesting.TestType1{})
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &runtimetesting.ExternalTestType1{})
s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{})
s.AddConversionFuncs(func(in *runtimetesting.TestType1, out *runtimetesting.ExternalTestType1, s conversion.Scope) {
out.A = in.A
})
return s
}
@ -540,6 +617,28 @@ func TestConvertToVersion(t *testing.T) {
gv: schema.GroupVersion{Version: "__internal"},
out: &runtimetesting.TestType1{A: "test"},
},
// converts from unstructured to internal
{
scheme: GetTestScheme(),
in: &runtimetesting.Unstructured{Object: map[string]interface{}{
"apiVersion": "custom/v1",
"kind": "TestType3",
"A": "test",
}},
gv: schema.GroupVersion{Version: "__internal"},
out: &runtimetesting.TestType1{A: "test"},
},
// converts from unstructured to external
{
scheme: GetTestScheme(),
in: &runtimetesting.Unstructured{Object: map[string]interface{}{
"apiVersion": "custom/v1",
"kind": "TestType3",
"A": "test",
}},
gv: schema.GroupVersion{Group: "custom", Version: "v1"},
out: &runtimetesting.ExternalTestType1{MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"}, A: "test"},
},
// prefers the best match
{
scheme: GetTestScheme(),
@ -711,51 +810,88 @@ func TestConvertToVersion(t *testing.T) {
},
}
for i, test := range testCases {
original := test.in.DeepCopyObject()
out, err := test.scheme.ConvertToVersion(test.in, test.gv)
switch {
case test.errFn != nil:
if !test.errFn(err) {
t.Errorf("%d: unexpected error: %v", i, err)
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
original := test.in.DeepCopyObject()
out, err := test.scheme.ConvertToVersion(test.in, test.gv)
switch {
case test.errFn != nil:
if !test.errFn(err) {
t.Fatalf("unexpected error: %v", err)
}
return
case err != nil:
t.Fatalf("unexpected error: %v", err)
}
if out == test.in {
t.Fatalf("ConvertToVersion should always copy out: %#v", out)
}
continue
case err != nil:
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if out == test.in {
t.Errorf("%d: ConvertToVersion should always copy out: %#v", i, out)
continue
}
if test.same {
if !reflect.DeepEqual(original, test.in) {
t.Errorf("%d: unexpected mutation of input: %s", i, diff.ObjectReflectDiff(original, test.in))
continue
if test.same {
if !reflect.DeepEqual(original, test.in) {
t.Fatalf("unexpected mutation of input: %s", diff.ObjectReflectDiff(original, test.in))
}
if !reflect.DeepEqual(out, test.out) {
t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out))
}
unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !reflect.DeepEqual(unsafe, test.out) {
t.Fatalf("unexpected unsafe: %s", diff.ObjectReflectDiff(unsafe, test.out))
}
if unsafe != test.in {
t.Fatalf("UnsafeConvertToVersion should return same object: %#v", unsafe)
}
return
}
if !reflect.DeepEqual(out, test.out) {
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
continue
t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out))
}
unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
})
}
}
func TestConvert(t *testing.T) {
testCases := []struct {
scheme *runtime.Scheme
in runtime.Object
into runtime.Object
gv runtime.GroupVersioner
out runtime.Object
errFn func(error) bool
}{
// converts from internal to unstructured, given a target version
{
scheme: GetTestScheme(),
in: &runtimetesting.TestType1{A: "test"},
into: &runtimetesting.Unstructured{},
out: &runtimetesting.Unstructured{Object: map[string]interface{}{
"myVersionKey": "custom/v1",
"myKindKey": "TestType3",
"A": "test",
}},
gv: schema.GroupVersion{Group: "custom", Version: "v1"},
},
}
for i, test := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
err := test.scheme.Convert(test.in, test.into, test.gv)
switch {
case test.errFn != nil:
if !test.errFn(err) {
t.Fatalf("unexpected error: %v", err)
}
return
case err != nil:
t.Fatalf("unexpected error: %v", err)
return
}
if !reflect.DeepEqual(unsafe, test.out) {
t.Errorf("%d: unexpected unsafe: %s", i, diff.ObjectReflectDiff(unsafe, test.out))
continue
if !reflect.DeepEqual(test.into, test.out) {
t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(test.into, test.out))
}
if unsafe != test.in {
t.Errorf("%d: UnsafeConvertToVersion should return same object: %#v", i, unsafe)
continue
}
continue
}
if !reflect.DeepEqual(out, test.out) {
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
continue
}
})
}
}

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["codec_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer",
library = ":go_default_library",
deps = [
"//vendor/github.com/ghodss/yaml:go_default_library",
@ -30,6 +31,7 @@ go_library(
"negotiated_codec.go",
"protobuf_extension.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["meta_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/json",
library = ":go_default_library",
)
@ -18,6 +19,7 @@ go_library(
"json.go",
"meta.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/json",
deps = [
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
@ -32,6 +34,7 @@ go_library(
go_test(
name = "go_default_xtest",
srcs = ["json_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/json_test",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

View file

@ -150,9 +150,10 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
}
if into != nil {
_, isUnstructured := into.(runtime.Unstructured)
types, _, err := s.typer.ObjectKinds(into)
switch {
case runtime.IsNotRegisteredError(err):
case runtime.IsNotRegisteredError(err), isUnstructured:
if err := jsoniter.ConfigFastest.Unmarshal(data, into); err != nil {
return nil, actual, err
}

View file

@ -11,6 +11,7 @@ go_library(
"doc.go",
"protobuf.go",
],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View file

@ -8,6 +8,7 @@ load(
go_library(
name = "go_default_library",
srcs = ["recognizer.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["streaming_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
library = ":go_default_library",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
@ -20,6 +21,7 @@ go_test(
go_library(
name = "go_default_library",
srcs = ["streaming.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["versioning_test.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
library = ":go_default_library",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
@ -20,10 +21,10 @@ go_test(
go_library(
name = "go_default_library",
srcs = ["versioning.go"],
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
deps = [
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
],
)

View file

@ -21,7 +21,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
// NewCodecForScheme is a convenience method for callers that are using a scheme.
@ -33,7 +32,7 @@ func NewCodecForScheme(
encodeVersion runtime.GroupVersioner,
decodeVersion runtime.GroupVersioner,
) runtime.Codec {
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, nil, encodeVersion, decodeVersion)
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, nil, encodeVersion, decodeVersion)
}
// NewDefaultingCodecForScheme is a convenience method for callers that are using a scheme.
@ -45,7 +44,7 @@ func NewDefaultingCodecForScheme(
encodeVersion runtime.GroupVersioner,
decodeVersion runtime.GroupVersioner,
) runtime.Codec {
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, scheme, encodeVersion, decodeVersion)
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, encodeVersion, decodeVersion)
}
// NewCodec takes objects in their internal versions and converts them to external versions before
@ -56,7 +55,6 @@ func NewCodec(
decoder runtime.Decoder,
convertor runtime.ObjectConvertor,
creater runtime.ObjectCreater,
copier runtime.ObjectCopier,
typer runtime.ObjectTyper,
defaulter runtime.ObjectDefaulter,
encodeVersion runtime.GroupVersioner,
@ -67,7 +65,6 @@ func NewCodec(
decoder: decoder,
convertor: convertor,
creater: creater,
copier: copier,
typer: typer,
defaulter: defaulter,
@ -82,7 +79,6 @@ type codec struct {
decoder runtime.Decoder
convertor runtime.ObjectConvertor
creater runtime.ObjectCreater
copier runtime.ObjectCopier
typer runtime.ObjectTyper
defaulter runtime.ObjectDefaulter
@ -123,12 +119,7 @@ func (c *codec) Decode(data []byte, defaultGVK *schema.GroupVersionKind, into ru
if c.defaulter != nil {
// create a copy to ensure defaulting is not applied to the original versioned objects
if isVersioned {
copied, err := c.copier.Copy(obj)
if err != nil {
utilruntime.HandleError(err)
copied = obj
}
versioned.Objects = []runtime.Object{copied}
versioned.Objects = []runtime.Object{obj.DeepCopyObject()}
}
c.defaulter.Default(obj)
} else {
@ -151,12 +142,7 @@ func (c *codec) Decode(data []byte, defaultGVK *schema.GroupVersionKind, into ru
// Convert if needed.
if isVersioned {
// create a copy, because ConvertToVersion does not guarantee non-mutation of objects
copied, err := c.copier.Copy(obj)
if err != nil {
utilruntime.HandleError(err)
copied = obj
}
versioned.Objects = []runtime.Object{copied}
versioned.Objects = []runtime.Object{obj.DeepCopyObject()}
}
// perform defaulting if requested

View file

@ -38,11 +38,8 @@ func (d *testDecodable) GetObjectKind() schema.ObjectKind { retur
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
func (d *testDecodable) DeepCopyObject() runtime.Object {
if d == nil {
return nil
}
clone := *d
return &clone
// no real deepcopy because these tests check for pointer equality
return d
}
type testNestedDecodable struct {
@ -58,11 +55,8 @@ func (d *testNestedDecodable) GetObjectKind() schema.ObjectKind {
func (d *testNestedDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
func (d *testNestedDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
func (d *testNestedDecodable) DeepCopyObject() runtime.Object {
if d == nil {
return nil
}
clone := *d
return &clone
// no real deepcopy because these tests check for pointer equality
return d
}
func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error {
@ -78,7 +72,7 @@ func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
func TestNestedDecode(t *testing.T) {
n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
decoder := &mockSerializer{obj: n}
codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil, nil)
codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil)
if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr {
t.Errorf("unexpected error: %v", err)
}
@ -94,7 +88,7 @@ func TestNestedEncode(t *testing.T) {
codec := NewCodec(
encoder, nil,
&checkConvertor{obj: n2, groupVersion: schema.GroupVersion{Group: "other"}},
nil, nil,
nil,
&mockTyper{gvks: []schema.GroupVersionKind{{Kind: "test"}}},
nil,
schema.GroupVersion{Group: "other"}, nil,
@ -118,7 +112,6 @@ func TestDecode(t *testing.T) {
serializer runtime.Serializer
convertor runtime.ObjectConvertor
creater runtime.ObjectCreater
copier runtime.ObjectCopier
typer runtime.ObjectTyper
defaulter runtime.ObjectDefaulter
yaml bool
@ -191,17 +184,6 @@ func TestDecode(t *testing.T) {
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
decodes: schema.GroupVersion{Group: "other", Version: "__internal"},
},
{
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
@ -223,7 +205,6 @@ func TestDecode(t *testing.T) {
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}},
copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
},
@ -243,7 +224,6 @@ func TestDecode(t *testing.T) {
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "something", Version: "else"}}},
copier: &checkCopy{in: decodable1, obj: decodable1, err: nil},
expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
},
@ -251,7 +231,7 @@ func TestDecode(t *testing.T) {
for i, test := range testCases {
t.Logf("%d", i)
s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.copier, test.typer, test.defaulter, test.encodes, test.decodes)
s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.typer, test.defaulter, test.encodes, test.decodes)
obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into)
if !reflect.DeepEqual(test.expectedGVK, gvk) {
@ -295,18 +275,6 @@ func TestDecode(t *testing.T) {
}
}
type checkCopy struct {
in, obj runtime.Object
err error
}
func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
if c.in != nil && c.in != obj {
return nil, fmt.Errorf("unexpected input to copy: %#v", obj)
}
return c.obj, c.err
}
type checkConvertor struct {
err error
in, obj runtime.Object

View file

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2017 The Kubernetes Authors.
Copyright 2018 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.
@ -20,31 +20,6 @@ limitations under the License.
package runtime
import (
conversion "k8s.io/apimachinery/pkg/conversion"
reflect "reflect"
)
// GetGeneratedDeepCopyFuncs returns the generated funcs, since we aren't registering them.
//
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
func GetGeneratedDeepCopyFuncs() []conversion.GeneratedDeepCopyFunc {
return []conversion.GeneratedDeepCopyFunc{
{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*RawExtension).DeepCopyInto(out.(*RawExtension))
return nil
}, InType: reflect.TypeOf(&RawExtension{})},
{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*Unknown).DeepCopyInto(out.(*Unknown))
return nil
}, InType: reflect.TypeOf(&Unknown{})},
{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*VersionedObjects).DeepCopyInto(out.(*VersionedObjects))
return nil
}, InType: reflect.TypeOf(&VersionedObjects{})},
}
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RawExtension) DeepCopyInto(out *RawExtension) {
*out = *in