Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -1,178 +1,186 @@
{
"ImportPath": "k8s.io/apimachinery",
"GoVersion": "go1.9",
"GodepVersion": "v79",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "782f4967f2dc4564575ca782fe2d04090b5faca8"
},
{
"ImportPath": "github.com/docker/spdystream",
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
},
{
"ImportPath": "github.com/docker/spdystream/spdy",
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
},
{
"ImportPath": "github.com/elazarl/goproxy",
"Rev": "c4fc26588b6ef8af07a191fcb6476387bdd46711"
},
{
"ImportPath": "github.com/evanphx/json-patch",
"Rev": "944e07253867aacae43c04b2e6a239005443f33a"
},
{
"ImportPath": "github.com/ghodss/yaml",
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
},
{
"ImportPath": "github.com/gogo/protobuf/sortkeys",
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
},
{
"ImportPath": "github.com/golang/glog",
"Rev": "44145f04b68cf362d9c4df2182967c2275eaefed"
},
{
"ImportPath": "github.com/golang/groupcache/lru",
"Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433"
},
{
"ImportPath": "github.com/golang/protobuf/proto",
"Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes",
"Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/any",
"Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
"Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/timestamp",
"Rev": "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
},
{
"ImportPath": "github.com/google/gofuzz",
"Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c"
},
{
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/hashicorp/golang-lru",
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
},
{
"ImportPath": "github.com/hashicorp/golang-lru/simplelru",
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
},
{
"ImportPath": "github.com/json-iterator/go",
"Rev": "13f86432b882000a51c6e610c620974462691a97"
},
{
"ImportPath": "github.com/mxk/go-flowrate/flowrate",
"Rev": "cca7078d478f8520f85629ad7c68962d31ed7682"
},
{
"ImportPath": "github.com/pborman/uuid",
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
},
{
"ImportPath": "github.com/pmezard/go-difflib/difflib",
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "4c012f6dcd9546820e378d0bdda4d8fc772cdfea"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
"Rev": "f6abca593680b2315d2075e0f5e2a9751e3f431a"
},
{
"ImportPath": "github.com/stretchr/testify/require",
"Rev": "f6abca593680b2315d2075e0f5e2a9751e3f431a"
},
{
"ImportPath": "golang.org/x/net/html",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/html/atom",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/http2",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/http2/hpack",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/idna",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/lex/httplex",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/net/websocket",
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
},
{
"ImportPath": "golang.org/x/text/secure/bidirule",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/transform",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/bidi",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/norm",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "gopkg.in/inf.v0",
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
},
{
"ImportPath": "gopkg.in/yaml.v2",
"Rev": "670d4cfef0544295bc27a114dbac37980d83185a"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
}
]
"ImportPath": "k8s.io/apimachinery",
"GoVersion": "go1.11",
"GodepVersion": "v80",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "782f4967f2dc4564575ca782fe2d04090b5faca8"
},
{
"ImportPath": "github.com/docker/spdystream",
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
},
{
"ImportPath": "github.com/docker/spdystream/spdy",
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
},
{
"ImportPath": "github.com/elazarl/goproxy",
"Rev": "c4fc26588b6ef8af07a191fcb6476387bdd46711"
},
{
"ImportPath": "github.com/evanphx/json-patch",
"Rev": "36442dbdb585210f8d5a1b45e67aa323c197d5c4"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
"Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02"
},
{
"ImportPath": "github.com/gogo/protobuf/sortkeys",
"Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02"
},
{
"ImportPath": "github.com/golang/groupcache/lru",
"Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433"
},
{
"ImportPath": "github.com/golang/protobuf/proto",
"Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes",
"Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/any",
"Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
"Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/timestamp",
"Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265"
},
{
"ImportPath": "github.com/google/gofuzz",
"Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c"
},
{
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
},
{
"ImportPath": "github.com/hashicorp/golang-lru",
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
},
{
"ImportPath": "github.com/hashicorp/golang-lru/simplelru",
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
},
{
"ImportPath": "github.com/json-iterator/go",
"Rev": "ab8a2e0c74be9d3be70b3184d9acc634935ded82"
},
{
"ImportPath": "github.com/modern-go/concurrent",
"Rev": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
},
{
"ImportPath": "github.com/modern-go/reflect2",
"Rev": "94122c33edd36123c84d5368cfb2b69df93a0ec8"
},
{
"ImportPath": "github.com/mxk/go-flowrate/flowrate",
"Rev": "cca7078d478f8520f85629ad7c68962d31ed7682"
},
{
"ImportPath": "github.com/pborman/uuid",
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
},
{
"ImportPath": "github.com/pmezard/go-difflib/difflib",
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "583c0c0531f06d5278b7d917446061adc344b5cd"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
"Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69"
},
{
"ImportPath": "github.com/stretchr/testify/require",
"Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69"
},
{
"ImportPath": "golang.org/x/net/html",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/html/atom",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/http2",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/http2/hpack",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/idna",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/lex/httplex",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/websocket",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/text/secure/bidirule",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/transform",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/bidi",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/unicode/norm",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "gopkg.in/inf.v0",
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
},
{
"ImportPath": "gopkg.in/yaml.v2",
"Rev": "5420a8b6744d3b0345ab293f6fcba19c978f1183"
},
{
"ImportPath": "k8s.io/klog",
"Rev": "8139d8cb77af419532b33dfa7dd09fbc5f1d344f"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
"Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",
"Rev": "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
}
]
}

2
vendor/k8s.io/apimachinery/OWNERS generated vendored
View File

@ -19,3 +19,5 @@ reviewers:
- sttts
- ncdc
- tallclair
labels:
- sig/api-machinery

17
vendor/k8s.io/apimachinery/SECURITY_CONTACTS generated vendored Normal file
View File

@ -0,0 +1,17 @@
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Product Security Team to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
cjcullen
jessfraz
liggitt
philips
tallclair

116
vendor/k8s.io/apimachinery/pkg/api/apitesting/codec.go generated vendored Normal file
View File

@ -0,0 +1,116 @@
/*
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 apitesting
import (
"fmt"
"mime"
"os"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
)
var (
testCodecMediaType string
testStorageCodecMediaType string
)
// TestCodec returns the codec for the API version to test against, as set by the
// KUBE_TEST_API_TYPE env var.
func TestCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
if len(testCodecMediaType) != 0 {
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testCodecMediaType)
if !ok {
panic(fmt.Sprintf("no serializer for %s", testCodecMediaType))
}
return codecs.CodecForVersions(serializerInfo.Serializer, codecs.UniversalDeserializer(), schema.GroupVersions(gvs), nil)
}
return codecs.LegacyCodec(gvs...)
}
// TestStorageCodec returns the codec for the API version to test against used in storage, as set by the
// KUBE_TEST_API_STORAGE_TYPE env var.
func TestStorageCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
if len(testStorageCodecMediaType) != 0 {
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testStorageCodecMediaType)
if !ok {
panic(fmt.Sprintf("no serializer for %s", testStorageCodecMediaType))
}
// etcd2 only supports string data - we must wrap any result before returning
// TODO: remove for etcd3 / make parameterizable
serializer := serializerInfo.Serializer
if !serializerInfo.EncodesAsText {
serializer = runtime.NewBase64Serializer(serializer, serializer)
}
decoder := recognizer.NewDecoder(serializer, codecs.UniversalDeserializer())
return codecs.CodecForVersions(serializer, decoder, schema.GroupVersions(gvs), nil)
}
return codecs.LegacyCodec(gvs...)
}
func init() {
var err error
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
testCodecMediaType, _, err = mime.ParseMediaType(apiMediaType)
if err != nil {
panic(err)
}
}
if storageMediaType := os.Getenv("KUBE_TEST_API_STORAGE_TYPE"); len(storageMediaType) > 0 {
testStorageCodecMediaType, _, err = mime.ParseMediaType(storageMediaType)
if err != nil {
panic(err)
}
}
}
// InstallOrDieFunc mirrors install functions that require success
type InstallOrDieFunc func(scheme *runtime.Scheme)
// SchemeForInstallOrDie builds a simple test scheme and codecfactory pair for easy unit testing from higher level install methods
func SchemeForInstallOrDie(installFns ...InstallOrDieFunc) (*runtime.Scheme, runtimeserializer.CodecFactory) {
scheme := runtime.NewScheme()
codecFactory := runtimeserializer.NewCodecFactory(scheme)
for _, installFn := range installFns {
installFn(scheme)
}
return scheme, codecFactory
}
// InstallFunc mirrors install functions that can return an error
type InstallFunc func(scheme *runtime.Scheme) error
// SchemeForOrDie builds a simple test scheme and codecfactory pair for easy unit testing from the bare registration methods.
func SchemeForOrDie(installFns ...InstallFunc) (*runtime.Scheme, runtimeserializer.CodecFactory) {
scheme := runtime.NewScheme()
codecFactory := runtimeserializer.NewCodecFactory(scheme)
for _, installFn := range installFns {
if err := installFn(scheme); err != nil {
panic(err)
}
}
return scheme, codecFactory
}

View File

@ -0,0 +1,415 @@
/*
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 roundtrip
import (
"bytes"
"encoding/hex"
"math/rand"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/golang/protobuf/proto"
"github.com/google/gofuzz"
flag "github.com/spf13/pflag"
apitesting "k8s.io/apimachinery/pkg/api/apitesting"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets"
)
type InstallFunc func(scheme *runtime.Scheme)
// RoundTripTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
// enough information to round trip
func RoundTripTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
scheme := runtime.NewScheme()
installFn(scheme)
RoundTripTestForScheme(t, scheme, fuzzingFuncs)
}
// RoundTripTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
func RoundTripTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
codecFactory := runtimeserializer.NewCodecFactory(scheme)
f := fuzzer.FuzzerFor(
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
rand.NewSource(rand.Int63()),
codecFactory,
)
RoundTripTypesWithoutProtobuf(t, scheme, codecFactory, f, nil)
}
// RoundTripProtobufTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
// enough information to round trip
func RoundTripProtobufTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
scheme := runtime.NewScheme()
installFn(scheme)
RoundTripProtobufTestForScheme(t, scheme, fuzzingFuncs)
}
// RoundTripProtobufTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
func RoundTripProtobufTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
codecFactory := runtimeserializer.NewCodecFactory(scheme)
fuzzer := fuzzer.FuzzerFor(
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
rand.NewSource(rand.Int63()),
codecFactory,
)
RoundTripTypes(t, scheme, codecFactory, fuzzer, nil)
}
var FuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
// globalNonRoundTrippableTypes are kinds that are effectively reserved across all GroupVersions
// They don't roundtrip
var globalNonRoundTrippableTypes = sets.NewString(
"ExportOptions",
"GetOptions",
// WatchEvent does not include kind and version and can only be deserialized
// implicitly (if the caller expects the specific object). The watch call defines
// the schema by content type, rather than via kind/version included in each
// object.
"WatchEvent",
// ListOptions is now part of the meta group
"ListOptions",
// Delete options is only read in metav1
"DeleteOptions",
)
// RoundTripTypesWithoutProtobuf applies the round-trip test to all round-trippable Kinds
// in the scheme. It will skip all the GroupVersionKinds in the skip list.
func RoundTripTypesWithoutProtobuf(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
}
func RoundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
}
func roundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
for _, group := range groupsFromScheme(scheme) {
t.Logf("starting group %q", group)
internalVersion := schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal}
internalKindToGoType := scheme.KnownTypes(internalVersion)
for kind := range internalKindToGoType {
if globalNonRoundTrippableTypes.Has(kind) {
continue
}
internalGVK := internalVersion.WithKind(kind)
roundTripSpecificKind(t, internalGVK, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, skipProtobuf)
}
t.Logf("finished group %q", group)
}
}
// RoundTripExternalTypes applies the round-trip test to all external round-trippable Kinds
// in the scheme. It will skip all the GroupVersionKinds in the nonRoundTripExternalTypes list .
func RoundTripExternalTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
kinds := scheme.AllKnownTypes()
for gvk := range kinds {
if gvk.Version == runtime.APIVersionInternal || globalNonRoundTrippableTypes.Has(gvk.Kind) {
continue
}
// FIXME: this is explicitly testing w/o protobuf which was failing if enabled
// the reason for that is that protobuf is not setting Kind and APIVersion fields
// during obj2 decode, the same then applies to DecodeInto obj3. My guess is we
// should be setting these two fields accordingly when protobuf is passed as codec
// to roundTrip method.
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
}
}
func RoundTripSpecificKindWithoutProtobuf(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
}
func RoundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
}
func roundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
if nonRoundTrippableTypes[gvk] {
t.Logf("skipping %v", gvk)
return
}
t.Logf("round tripping %v", gvk)
// Try a few times, since runTest uses random values.
for i := 0; i < *FuzzIters; i++ {
if gvk.Version == runtime.APIVersionInternal {
roundTripToAllExternalVersions(t, scheme, codecFactory, fuzzer, gvk, nonRoundTrippableTypes, skipProtobuf)
} else {
roundTripOfExternalType(t, scheme, codecFactory, fuzzer, gvk, skipProtobuf)
}
if t.Failed() {
break
}
}
}
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
// fuzzer registered with the apitesting package.
func fuzzInternalObject(t *testing.T, fuzzer *fuzz.Fuzzer, object runtime.Object) runtime.Object {
fuzzer.Fuzz(object)
j, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("Unexpected error %v for %#v", err, object)
}
j.SetKind("")
j.SetAPIVersion("")
return object
}
func groupsFromScheme(scheme *runtime.Scheme) []string {
ret := sets.String{}
for gvk := range scheme.AllKnownTypes() {
ret.Insert(gvk.Group)
}
return ret.List()
}
func roundTripToAllExternalVersions(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, internalGVK schema.GroupVersionKind, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
object, err := scheme.New(internalGVK)
if err != nil {
t.Fatalf("Couldn't make a %v? %v", internalGVK, err)
}
if _, err := apimeta.TypeAccessor(object); err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", internalGVK, err)
}
fuzzInternalObject(t, fuzzer, object)
// find all potential serializations in the scheme.
// TODO fix this up to handle kinds that cross registered with different names.
for externalGVK, externalGoType := range scheme.AllKnownTypes() {
if externalGVK.Version == runtime.APIVersionInternal {
continue
}
if externalGVK.GroupKind() != internalGVK.GroupKind() {
continue
}
if nonRoundTrippableTypes[externalGVK] {
t.Logf("\tskipping %v %v", externalGVK, externalGoType)
continue
}
t.Logf("\tround tripping to %v %v", externalGVK, externalGoType)
roundTrip(t, scheme, apitesting.TestCodec(codecFactory, externalGVK.GroupVersion()), object)
// TODO remove this hack after we're past the intermediate steps
if !skipProtobuf && externalGVK.Group != "kubeadm.k8s.io" {
s := protobuf.NewSerializer(scheme, scheme, "application/arbitrary.content.type")
protobufCodec := codecFactory.CodecForVersions(s, s, externalGVK.GroupVersion(), nil)
roundTrip(t, scheme, protobufCodec, object)
}
}
}
func roundTripOfExternalType(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, externalGVK schema.GroupVersionKind, skipProtobuf bool) {
object, err := scheme.New(externalGVK)
if err != nil {
t.Fatalf("Couldn't make a %v? %v", externalGVK, err)
}
typeAcc, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", externalGVK, err)
}
fuzzInternalObject(t, fuzzer, object)
externalGoType := reflect.TypeOf(object).PkgPath()
t.Logf("\tround tripping external type %v %v", externalGVK, externalGoType)
typeAcc.SetKind(externalGVK.Kind)
typeAcc.SetAPIVersion(externalGVK.GroupVersion().String())
roundTrip(t, scheme, json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false), object)
// TODO remove this hack after we're past the intermediate steps
if !skipProtobuf {
roundTrip(t, scheme, protobuf.NewSerializer(scheme, scheme, "application/protobuf"), object)
}
}
// roundTrip applies a single round-trip test to the given runtime object
// using the given codec. The round-trip test ensures that an object can be
// deep-copied, converted, marshaled and back without loss of data.
//
// For internal types this means
//
// internal -> external -> json/protobuf -> external -> internal.
//
// For external types this means
//
// external -> json/protobuf -> external.
func roundTrip(t *testing.T, scheme *runtime.Scheme, codec runtime.Codec, object runtime.Object) {
printer := spew.ConfigState{DisableMethods: true}
original := object
// deep copy the original object
object = object.DeepCopyObject()
name := reflect.TypeOf(object).Elem().Name()
if !apiequality.Semantic.DeepEqual(original, object) {
t.Errorf("%v: DeepCopy altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
t.Errorf("%s", spew.Sdump(original))
t.Errorf("%s", spew.Sdump(object))
return
}
// encode (serialize) the deep copy using the provided codec
data, err := runtime.Encode(codec, object)
if err != nil {
if runtime.IsNotRegisteredError(err) {
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
} else {
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
}
return
}
// ensure that the deep copy is equal to the original; neither the deep
// copy or conversion should alter the object
// TODO eliminate this global
if !apiequality.Semantic.DeepEqual(original, object) {
t.Errorf("%v: encode altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
return
}
// encode (serialize) a second time to verify that it was not varying
secondData, err := runtime.Encode(codec, object)
if err != nil {
if runtime.IsNotRegisteredError(err) {
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
} else {
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
}
return
}
// serialization to the wire must be stable to ensure that we don't write twice to the DB
// when the object hasn't changed.
if !bytes.Equal(data, secondData) {
t.Errorf("%v: serialization is not stable: %s", name, printer.Sprintf("%#v", object))
}
// decode (deserialize) the encoded data back into an object
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Errorf("%v: %v\nCodec: %#v\nData: %s\nSource: %#v", name, err, codec, dataAsString(data), printer.Sprintf("%#v", object))
panic("failed")
}
// ensure that the object produced from decoding the encoded data is equal
// to the original object
if !apiequality.Semantic.DeepEqual(original, obj2) {
t.Errorf("%v: diff: %v\nCodec: %#v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, diff.ObjectReflectDiff(original, obj2), codec, printer.Sprintf("%#v", original), dataAsString(data), printer.Sprintf("%#v", obj2))
return
}
// decode the encoded data into a new object (instead of letting the codec
// create a new object)
obj3 := reflect.New(reflect.TypeOf(object).Elem()).Interface().(runtime.Object)
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Errorf("%v: %v", name, err)
return
}
// special case for kinds which are internal and external at the same time (many in meta.k8s.io are). For those
// runtime.DecodeInto above will return the external variant and set the APIVersion and kind, while the input
// object might be internal. Hence, we clear those values for obj3 for that case to correctly compare.
intAndExt, err := internalAndExternalKind(scheme, object)
if err != nil {
t.Errorf("%v: %v", name, err)
return
}
if intAndExt {
typeAcc, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
}
if len(typeAcc.GetAPIVersion()) == 0 {
typeAcc, err := apimeta.TypeAccessor(obj3)
if err != nil {
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
}
typeAcc.SetAPIVersion("")
typeAcc.SetKind("")
}
}
// ensure that the new runtime object is equal to the original after being
// decoded into
if !apiequality.Semantic.DeepEqual(object, obj3) {
t.Errorf("%v: diff: %v\nCodec: %#v", name, diff.ObjectReflectDiff(object, obj3), codec)
return
}
// do structure-preserving fuzzing of the deep-copied object. If it shares anything with the original,
// the deep-copy was actually only a shallow copy. Then original and obj3 will be different after fuzzing.
// NOTE: we use the encoding+decoding here as an alternative, guaranteed deep-copy to compare against.
fuzzer.ValueFuzz(object)
if !apiequality.Semantic.DeepEqual(original, obj3) {
t.Errorf("%v: fuzzing a copy altered the original, diff: %v", name, diff.ObjectReflectDiff(original, obj3))
return
}
}
func internalAndExternalKind(scheme *runtime.Scheme, object runtime.Object) (bool, error) {
kinds, _, err := scheme.ObjectKinds(object)
if err != nil {
return false, err
}
internal, external := false, false
for _, k := range kinds {
if k.Version == runtime.APIVersionInternal {
internal = true
} else {
external = true
}
}
return internal && external, nil
}
// dataAsString returns the given byte array as a string; handles detecting
// protocol buffers.
func dataAsString(data []byte) string {
dataString := string(data)
if !strings.HasPrefix(dataString, "{") {
dataString = "\n" + hex.Dump(data)
proto.NewBuffer(make([]byte, 0, 1024)).DebugPrint("decoded object", data)
}
return dataString
}

View File

@ -1,32 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["semantic.go"],
importpath = "k8s.io/apimachinery/pkg/api/equality",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,47 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["errors_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/util/validation/field:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"errors.go",
],
importpath = "k8s.io/apimachinery/pkg/api/errors",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -82,7 +83,20 @@ func (u *UnexpectedObjectError) Error() string {
func FromObject(obj runtime.Object) error {
switch t := obj.(type) {
case *metav1.Status:
return &StatusError{*t}
return &StatusError{ErrStatus: *t}
case runtime.Unstructured:
var status metav1.Status
obj := t.UnstructuredContent()
if !reflect.DeepEqual(obj["kind"], "Status") {
break
}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(t.UnstructuredContent(), &status); err != nil {
return err
}
if status.APIVersion != "v1" && status.APIVersion != "meta.k8s.io/v1" {
break
}
return &StatusError{ErrStatus: status}
}
return &UnexpectedObjectError{obj}
}

View File

@ -1,72 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"meta_test.go",
"multirestmapper_test.go",
"priority_test.go",
"restmapper_test.go",
],
embed = [":go_default_library"],
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1: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/util/diff:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"errors.go",
"firsthit_restmapper.go",
"help.go",
"interfaces.go",
"lazy.go",
"meta.go",
"multirestmapper.go",
"priority.go",
"restmapper.go",
"unstructured.go",
],
importpath = "k8s.io/apimachinery/pkg/api/meta",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1: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/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/meta/table:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -23,12 +23,6 @@ import (
"k8s.io/apimachinery/pkg/types"
)
// VersionInterfaces contains the interfaces one should use for dealing with types of a particular version.
type VersionInterfaces struct {
runtime.ObjectConvertor
MetadataAccessor
}
type ListMetaAccessor interface {
GetListMeta() List
}
@ -92,28 +86,19 @@ const (
type RESTScope interface {
// Name of the scope
Name() RESTScopeName
// ParamName is the optional name of the parameter that should be inserted in the resource url
// If empty, no param will be inserted
ParamName() string
// ArgumentName is the optional name that should be used for the variable holding the value.
ArgumentName() string
// ParamDescription is the optional description to use to document the parameter in api documentation
ParamDescription() string
}
// RESTMapping contains the information needed to deal with objects of a specific
// resource and kind in a RESTful manner.
type RESTMapping struct {
// Resource is a string representing the name of this resource as a REST client would see it
Resource string
// Resource is the GroupVersionResource (location) for this endpoint
Resource schema.GroupVersionResource
// GroupVersionKind is the GroupVersionKind (data format) to submit to this endpoint
GroupVersionKind schema.GroupVersionKind
// Scope contains the information needed to deal with REST Resources that are in a resource hierarchy
Scope RESTScope
runtime.ObjectConvertor
MetadataAccessor
}
// RESTMapper allows clients to map resources to kind, and map kind and version

View File

@ -19,27 +19,25 @@ package meta
import (
"sync"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// lazyObject defers loading the mapper and typer until necessary.
type lazyObject struct {
loader func() (RESTMapper, runtime.ObjectTyper, error)
loader func() (RESTMapper, error)
lock sync.Mutex
loaded bool
err error
mapper RESTMapper
typer runtime.ObjectTyper
}
// NewLazyObjectLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by
// returning those initialization errors when the interface methods are invoked. This defers the
// initialization and any server calls until a client actually needs to perform the action.
func NewLazyObjectLoader(fn func() (RESTMapper, runtime.ObjectTyper, error)) (RESTMapper, runtime.ObjectTyper) {
func NewLazyRESTMapperLoader(fn func() (RESTMapper, error)) RESTMapper {
obj := &lazyObject{loader: fn}
return obj, obj
return obj
}
// init lazily loads the mapper and typer, returning an error if initialization has failed.
@ -49,13 +47,12 @@ func (o *lazyObject) init() error {
if o.loaded {
return o.err
}
o.mapper, o.typer, o.err = o.loader()
o.mapper, o.err = o.loader()
o.loaded = true
return o.err
}
var _ RESTMapper = &lazyObject{}
var _ runtime.ObjectTyper = &lazyObject{}
func (o *lazyObject) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
if err := o.init(); err != nil {
@ -105,17 +102,3 @@ func (o *lazyObject) ResourceSingularizer(resource string) (singular string, err
}
return o.mapper.ResourceSingularizer(resource)
}
func (o *lazyObject) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
if err := o.init(); err != nil {
return nil, false, err
}
return o.typer.ObjectKinds(obj)
}
func (o *lazyObject) Recognizes(gvk schema.GroupVersionKind) bool {
if err := o.init(); err != nil {
return false
}
return o.typer.Recognizes(gvk)
}

View File

@ -20,7 +20,7 @@ import (
"fmt"
"reflect"
"github.com/golang/glog"
"k8s.io/klog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
@ -38,7 +38,6 @@ var errNotCommon = fmt.Errorf("object does not implement the common interface fo
// CommonAccessor returns a Common interface for the provided object or an error if the object does
// not provide List.
// TODO: return bool instead of error
func CommonAccessor(obj interface{}) (metav1.Common, error) {
switch t := obj.(type) {
case List:
@ -71,7 +70,6 @@ func CommonAccessor(obj interface{}) (metav1.Common, error) {
// not provide List.
// IMPORTANT: Objects are NOT a superset of lists. Do not use this check to determine whether an
// object *is* a List.
// TODO: return bool instead of error
func ListAccessor(obj interface{}) (List, error) {
switch t := obj.(type) {
case List:
@ -101,7 +99,6 @@ var errNotObject = fmt.Errorf("object does not implement the Object interfaces")
// obj must be a pointer to an API type. An error is returned if the minimum
// required fields are missing. Fields that are not required return the default
// value and are a no-op if set.
// TODO: return bool instead of error
func Accessor(obj interface{}) (metav1.Object, error) {
switch t := obj.(type) {
case metav1.Object:
@ -135,12 +132,12 @@ func AsPartialObjectMetadata(m metav1.Object) *metav1beta1.PartialObjectMetadata
CreationTimestamp: m.GetCreationTimestamp(),
DeletionTimestamp: m.GetDeletionTimestamp(),
DeletionGracePeriodSeconds: m.GetDeletionGracePeriodSeconds(),
Labels: m.GetLabels(),
Annotations: m.GetAnnotations(),
OwnerReferences: m.GetOwnerReferences(),
Finalizers: m.GetFinalizers(),
ClusterName: m.GetClusterName(),
Initializers: m.GetInitializers(),
Labels: m.GetLabels(),
Annotations: m.GetAnnotations(),
OwnerReferences: m.GetOwnerReferences(),
Finalizers: m.GetFinalizers(),
ClusterName: m.GetClusterName(),
Initializers: m.GetInitializers(),
},
}
}
@ -610,7 +607,7 @@ func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
var ret []metav1.OwnerReference
s := a.ownerReferences
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
glog.Errorf("expect %v to be a pointer to slice", s)
klog.Errorf("expect %v to be a pointer to slice", s)
return ret
}
s = s.Elem()
@ -618,7 +615,7 @@ func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
ret = make([]metav1.OwnerReference, s.Len(), s.Len()+1)
for i := 0; i < s.Len(); i++ {
if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil {
glog.Errorf("extractFromOwnerReference failed: %v", err)
klog.Errorf("extractFromOwnerReference failed: %v", err)
return ret
}
}
@ -628,13 +625,13 @@ func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
func (a genericAccessor) SetOwnerReferences(references []metav1.OwnerReference) {
s := a.ownerReferences
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
glog.Errorf("expect %v to be a pointer to slice", s)
klog.Errorf("expect %v to be a pointer to slice", s)
}
s = s.Elem()
newReferences := reflect.MakeSlice(s.Type(), len(references), len(references))
for i := 0; i < len(references); i++ {
if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil {
glog.Errorf("setOwnerReference failed: %v", err)
klog.Errorf("setOwnerReference failed: %v", err)
return
}
}

View File

@ -54,12 +54,12 @@ func (m PriorityRESTMapper) String() string {
// ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit.
func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
originalGVRs, err := m.Delegate.ResourcesFor(partiallySpecifiedResource)
if err != nil {
return schema.GroupVersionResource{}, err
originalGVRs, originalErr := m.Delegate.ResourcesFor(partiallySpecifiedResource)
if originalErr != nil && len(originalGVRs) == 0 {
return schema.GroupVersionResource{}, originalErr
}
if len(originalGVRs) == 1 {
return originalGVRs[0], nil
return originalGVRs[0], originalErr
}
remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...)
@ -77,7 +77,7 @@ func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupV
continue
case 1:
// one match, return
return matchedGVRs[0], nil
return matchedGVRs[0], originalErr
default:
// more than one match, use the matched hits as the list moving to the next pattern.
// this way you can have a series of selection criteria
@ -90,12 +90,12 @@ func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupV
// KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit.
func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
originalGVKs, err := m.Delegate.KindsFor(partiallySpecifiedResource)
if err != nil {
return schema.GroupVersionKind{}, err
originalGVKs, originalErr := m.Delegate.KindsFor(partiallySpecifiedResource)
if originalErr != nil && len(originalGVKs) == 0 {
return schema.GroupVersionKind{}, originalErr
}
if len(originalGVKs) == 1 {
return originalGVKs[0], nil
return originalGVKs[0], originalErr
}
remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...)
@ -113,7 +113,7 @@ func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersi
continue
case 1:
// one match, return
return matchedGVKs[0], nil
return matchedGVKs[0], originalErr
default:
// more than one match, use the matched hits as the list moving to the next pattern.
// this way you can have a series of selection criteria
@ -153,9 +153,9 @@ func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind)
}
func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
mappings, err := m.Delegate.RESTMappings(gk, versions...)
if err != nil {
return nil, err
mappings, originalErr := m.Delegate.RESTMappings(gk, versions...)
if originalErr != nil && len(mappings) == 0 {
return nil, originalErr
}
// any versions the user provides take priority
@ -187,7 +187,7 @@ func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string)
continue
case 1:
// one match, return
return matching[0], nil
return matching[0], originalErr
default:
// more than one match, use the matched hits as the list moving to the next pattern.
// this way you can have a series of selection criteria
@ -195,7 +195,7 @@ func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string)
}
}
if len(remaining) == 1 {
return remaining[0], nil
return remaining[0], originalErr
}
var kinds []schema.GroupVersionKind

View File

@ -34,6 +34,30 @@ func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) {
result schema.GroupVersionResource
err string
}{
{
name: "error",
delegate: fixedRESTMapper{err: errors.New("delegateError")},
err: "delegateError",
},
{
name: "single hit + error",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}, err: errors.New("delegateError")},
result: schema.GroupVersionResource{Resource: "single-hit"},
err: "delegateError",
},
{
name: "group selection + error",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "two", Version: "b", Resource: "second"},
}, err: errors.New("delegateError")},
resourcePatterns: []schema.GroupVersionResource{
{Group: "one", Version: AnyVersion, Resource: AnyResource},
},
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
err: "delegateError",
},
{
name: "single hit",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}},
@ -106,6 +130,10 @@ func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) {
if len(tc.err) == 0 && actualErr == nil {
continue
}
if len(tc.err) == 0 && actualErr != nil {
t.Errorf("%s: unexpected err: %v", tc.name, actualErr)
continue
}
if len(tc.err) > 0 && actualErr == nil {
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
continue
@ -125,6 +153,30 @@ func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) {
result schema.GroupVersionKind
err string
}{
{
name: "error",
delegate: fixedRESTMapper{err: errors.New("delegateErr")},
err: "delegateErr",
},
{
name: "single hit + error",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}, err: errors.New("delegateErr")},
result: schema.GroupVersionKind{Kind: "single-hit"},
err: "delegateErr",
},
{
name: "group selection + error",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "two", Version: "b", Kind: "second"},
}, err: errors.New("delegateErr")},
kindPatterns: []schema.GroupVersionKind{
{Group: "one", Version: AnyVersion, Kind: AnyKind},
},
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
err: "delegateErr",
},
{
name: "single hit",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}},
@ -197,6 +249,10 @@ func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) {
if len(tc.err) == 0 && actualErr == nil {
continue
}
if len(tc.err) == 0 && actualErr != nil {
t.Errorf("%s: unexpected err: %v", tc.name, actualErr)
continue
}
if len(tc.err) > 0 && actualErr == nil {
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
continue
@ -248,6 +304,13 @@ func TestPriorityRESTMapperRESTMapping(t *testing.T) {
input: schema.GroupKind{Kind: "Foo"},
err: errors.New("fail on this"),
},
{
name: "result + error",
mapper: PriorityRESTMapper{Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}, err: errors.New("fail on this")}},
input: schema.GroupKind{Kind: "Foo"},
result: mapping1,
err: errors.New("fail on this"),
},
{
name: "return error for ambiguous",
mapper: PriorityRESTMapper{

View File

@ -28,30 +28,15 @@ import (
// Implements RESTScope interface
type restScope struct {
name RESTScopeName
paramName string
argumentName string
paramDescription string
name RESTScopeName
}
func (r *restScope) Name() RESTScopeName {
return r.name
}
func (r *restScope) ParamName() string {
return r.paramName
}
func (r *restScope) ArgumentName() string {
return r.argumentName
}
func (r *restScope) ParamDescription() string {
return r.paramDescription
}
var RESTScopeNamespace = &restScope{
name: RESTScopeNameNamespace,
paramName: "namespaces",
argumentName: "namespace",
paramDescription: "object name and auth scope, such as for teams and projects",
name: RESTScopeNameNamespace,
}
var RESTScopeRoot = &restScope{
@ -77,8 +62,6 @@ type DefaultRESTMapper struct {
kindToScope map[schema.GroupVersionKind]RESTScope
singularToPlural map[schema.GroupVersionResource]schema.GroupVersionResource
pluralToSingular map[schema.GroupVersionResource]schema.GroupVersionResource
interfacesFunc VersionInterfacesFunc
}
func (m *DefaultRESTMapper) String() string {
@ -87,16 +70,12 @@ func (m *DefaultRESTMapper) String() string {
var _ RESTMapper = &DefaultRESTMapper{}
// VersionInterfacesFunc returns the appropriate typer, and metadata accessor for a
// given api version, or an error if no such api version exists.
type VersionInterfacesFunc func(version schema.GroupVersion) (*VersionInterfaces, error)
// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion
// to a resource name and back based on the objects in a runtime.Scheme
// and the Kubernetes API conventions. Takes a group name, a priority list of the versions
// to search when an object has no default version (set empty to return an error),
// and a function that retrieves the correct metadata for a given version.
func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper {
func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion) *DefaultRESTMapper {
resourceToKind := make(map[schema.GroupVersionResource]schema.GroupVersionKind)
kindToPluralResource := make(map[schema.GroupVersionKind]schema.GroupVersionResource)
kindToScope := make(map[schema.GroupVersionKind]RESTScope)
@ -111,7 +90,6 @@ func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion, f VersionI
defaultGroupVersions: defaultGroupVersions,
singularToPlural: singularToPlural,
pluralToSingular: pluralToSingular,
interfacesFunc: f,
}
}
@ -526,18 +504,10 @@ func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion(), gvk.Kind)
}
interfaces, err := m.interfacesFunc(gvk.GroupVersion())
if err != nil {
return nil, fmt.Errorf("the provided version %q has no relevant versions: %v", gvk.GroupVersion().String(), err)
}
mappings = append(mappings, &RESTMapping{
Resource: res.Resource,
Resource: res,
GroupVersionKind: gvk,
Scope: scope,
ObjectConvertor: interfaces.ObjectConvertor,
MetadataAccessor: interfaces.MetadataAccessor,
})
}

View File

@ -17,42 +17,13 @@ limitations under the License.
package meta
import (
"errors"
"reflect"
"strings"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type fakeConvertor struct{}
func (fakeConvertor) Convert(in, out, context interface{}) error {
return nil
}
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ runtime.GroupVersioner) (runtime.Object, error) {
return in, nil
}
func (fakeConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
return label, value, nil
}
var validAccessor = resourceAccessor{}
var validConvertor = fakeConvertor{}
func fakeInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
return &VersionInterfaces{ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, nil
}
var unmatchedErr = errors.New("no version")
func unmatchedVersionInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
return nil, unmatchedErr
}
func TestRESTMapperVersionAndKindForResource(t *testing.T) {
testGroup := "test.group"
testVersion := "test"
@ -71,7 +42,7 @@ func TestRESTMapperVersionAndKindForResource(t *testing.T) {
{Resource: schema.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion})
if len(testCase.ExpectedGVK.Kind) != 0 {
mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace)
}
@ -104,7 +75,7 @@ func TestRESTMapperGroupForResource(t *testing.T) {
{Resource: schema.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testCase.GroupVersionKind.GroupVersion()})
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace)
actualGVK, err := mapper.KindFor(testCase.Resource)
@ -249,7 +220,7 @@ func TestRESTMapperKindsFor(t *testing.T) {
}
for _, testCase := range testCases {
tcName := testCase.Name
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
mapper := NewDefaultRESTMapper(testCase.PreferredOrder)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace)
}
@ -426,7 +397,7 @@ func TestRESTMapperResourcesFor(t *testing.T) {
tcName := testCase.Name
for _, partialResource := range []schema.GroupVersionResource{testCase.PluralPartialResourceToRequest, testCase.SingularPartialResourceToRequest} {
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
mapper := NewDefaultRESTMapper(testCase.PreferredOrder)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace)
}
@ -511,7 +482,7 @@ func TestRESTMapperResourceSingularizer(t *testing.T) {
{Kind: "lowercases", Plural: "lowercaseses", Singular: "lowercases"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion})
// create singular/plural mapping
mapper.Add(testGroupVersion.WithKind(testCase.Kind), RESTScopeNamespace)
@ -535,7 +506,7 @@ func TestRESTMapperRESTMapping(t *testing.T) {
APIGroupVersions []schema.GroupVersion
DefaultVersions []schema.GroupVersion
Resource string
Resource schema.GroupVersionResource
ExpectedGroupVersion *schema.GroupVersion
Err bool
}{
@ -544,19 +515,19 @@ func TestRESTMapperRESTMapping(t *testing.T) {
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{}, Resource: "internalobjects", ExpectedGroupVersion: &schema.GroupVersion{Group: testGroup, Version: "test"}},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{}, Resource: internalGroupVersion.WithResource("internalobjects"), ExpectedGroupVersion: &schema.GroupVersion{Group: testGroup, Version: "test"}},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")},
// TODO: add test for a resource that exists in one version but not another
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
mapper := NewDefaultRESTMapper(testCase.DefaultVersions)
mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace)
preferredVersions := []string{}
@ -577,10 +548,6 @@ func TestRESTMapperRESTMapping(t *testing.T) {
t.Errorf("%d: unexpected resource: %#v", i, mapping)
}
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
t.Errorf("%d: missing codec and accessor: %#v", i, mapping)
}
groupVersion := testCase.ExpectedGroupVersion
if groupVersion == nil {
groupVersion = &testCase.APIGroupVersions[0]
@ -599,7 +566,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
otherObjectGK := schema.GroupKind{Group: "tgroup", Kind: "OtherObject"}
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces)
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2})
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace)
@ -608,7 +575,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
if mapping.Resource != expectedGroupVersion2.WithResource("otherobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
t.Errorf("unexpected mapping: %#v", mapping)
}
@ -616,7 +583,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "internalobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
if mapping.Resource != expectedGroupVersion1.WithResource("internalobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
t.Errorf("unexpected mapping: %#v", mapping)
}
@ -646,7 +613,7 @@ func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
if mapping.Resource != expectedGroupVersion2.WithResource("otherobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
t.Errorf("unexpected mapping: %#v", mapping)
}
}
@ -678,7 +645,7 @@ func TestRESTMapperRESTMappings(t *testing.T) {
Kind: "InternalObject",
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}},
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
ExpectedRESTMappings: []*RESTMapping{{Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"}, GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
},
// ask for specific versions - only one available - check ExpectedRESTMappings
@ -687,20 +654,29 @@ func TestRESTMapperRESTMappings(t *testing.T) {
Kind: "InternalObject",
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v3"}, {Group: testGroup, Version: "v2"}},
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
ExpectedRESTMappings: []*RESTMapping{{Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"}, GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
},
// do not ask for specific version - search through default versions - check ExpectedRESTMappings
{
DefaultVersions: []schema.GroupVersion{testGroupVersion, {Group: testGroup, Version: "v2"}},
Kind: "InternalObject",
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v1"}.WithKind("InternalObject"), schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v1", Kind: "InternalObject"}}, {Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
DefaultVersions: []schema.GroupVersion{testGroupVersion, {Group: testGroup, Version: "v2"}},
Kind: "InternalObject",
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v1"}.WithKind("InternalObject"), schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
ExpectedRESTMappings: []*RESTMapping{
{
Resource: schema.GroupVersionResource{Group: testGroup, Version: "v1", Resource: "internalobjects"},
GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v1", Kind: "InternalObject"},
},
{
Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"},
GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"},
},
},
},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
mapper := NewDefaultRESTMapper(testCase.DefaultVersions)
for _, gvk := range testCase.AddGroupVersionKind {
mapper.Add(gvk, RESTScopeNamespace)
}
@ -727,9 +703,6 @@ func TestRESTMapperRESTMappings(t *testing.T) {
if mapping.Resource != exp.Resource {
t.Errorf("%d - %d: unexpected resource: %#v", i, j, mapping)
}
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
t.Errorf("%d - %d: missing codec and accessor: %#v", i, j, mapping)
}
if mapping.GroupVersionKind != exp.GroupVersionKind {
t.Errorf("%d - %d: unexpected GroupVersionKind: %#v", i, j, mapping)
}
@ -742,9 +715,9 @@ func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"}
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces)
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2})
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
_, err := mapper.RESTMapping(internalObjectGK, expectedGroupVersion1.Version)
_, err := mapper.RESTMapping(internalObjectGK, "test3")
if err == nil {
t.Errorf("unexpected non-error")
}

View File

@ -1,29 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["table.go"],
importpath = "k8s.io/apimachinery/pkg/api/meta/table",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/duration:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -53,7 +53,7 @@ func MetaToTableRow(obj runtime.Object, rowFn func(obj runtime.Object, m metav1.
row := metav1beta1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
row.Cells, err = rowFn(obj, m, m.GetName(), translateTimestamp(m.GetCreationTimestamp()))
row.Cells, err = rowFn(obj, m, m.GetName(), ConvertToHumanReadableDateType(m.GetCreationTimestamp()))
if err != nil {
return nil, err
}
@ -61,9 +61,9 @@ func MetaToTableRow(obj runtime.Object, rowFn func(obj runtime.Object, m metav1.
return rows, nil
}
// translateTimestamp returns the elapsed time since timestamp in
// ConvertToHumanReadableDateType returns the elapsed time since timestamp in
// human-readable approximation.
func translateTimestamp(timestamp metav1.Time) string {
func ConvertToHumanReadableDateType(timestamp metav1.Time) string {
if timestamp.IsZero() {
return "<unknown>"
}

View File

@ -0,0 +1,171 @@
/*
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.
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 testrestmapper
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
// TestOnlyStaticRESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. legacy kube group preferred version, extensions preferred version, metrics preferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
// TODO callers of this method should be updated to build their own specific restmapper based on their scheme for their tests
// TODO the things being tested are related to whether various cases are handled, not tied to the particular types being checked.
func TestOnlyStaticRESTMapper(scheme *runtime.Scheme, versionPatterns ...schema.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for _, enabledVersion := range scheme.PrioritizedVersionsAllGroups() {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
unionMapper = append(unionMapper, newRESTMapper(enabledVersion.Group, scheme))
}
}
if len(versionPatterns) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := prioritiesForGroups(scheme, prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for _, enabledVersion := range scheme.PrioritizedVersionsAllGroups() {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := prioritiesForGroups(scheme, remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func prioritiesForGroups(scheme *runtime.Scheme, groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, group := range groups {
availableVersions := scheme.PrioritizedVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
func newRESTMapper(group string, scheme *runtime.Scheme) meta.RESTMapper {
mapper := meta.NewDefaultRESTMapper(scheme.PrioritizedVersionsForGroup(group))
for _, gv := range scheme.PrioritizedVersionsForGroup(group) {
for kind := range scheme.KnownTypes(gv) {
if ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if rootScopedKinds[gv.WithKind(kind).GroupKind()] {
scope = meta.RESTScopeRoot
}
mapper.Add(gv.WithKind(kind), scope)
}
}
return mapper
}
// hardcoded is good enough for the test we're running
var rootScopedKinds = map[schema.GroupKind]bool{
{Group: "admission.k8s.io", Kind: "AdmissionReview"}: true,
{Group: "admissionregistration.k8s.io", Kind: "InitializerConfiguration"}: true,
{Group: "admissionregistration.k8s.io", Kind: "ValidatingWebhookConfiguration"}: true,
{Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration"}: true,
{Group: "authentication.k8s.io", Kind: "TokenReview"}: true,
{Group: "authorization.k8s.io", Kind: "SubjectAccessReview"}: true,
{Group: "authorization.k8s.io", Kind: "SelfSubjectAccessReview"}: true,
{Group: "authorization.k8s.io", Kind: "SelfSubjectRulesReview"}: true,
{Group: "certificates.k8s.io", Kind: "CertificateSigningRequest"}: true,
{Group: "", Kind: "Node"}: true,
{Group: "", Kind: "Namespace"}: true,
{Group: "", Kind: "PersistentVolume"}: true,
{Group: "", Kind: "ComponentStatus"}: true,
{Group: "extensions", Kind: "PodSecurityPolicy"}: true,
{Group: "policy", Kind: "PodSecurityPolicy"}: true,
{Group: "extensions", Kind: "PodSecurityPolicy"}: true,
{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}: true,
{Group: "rbac.authorization.k8s.io", Kind: "ClusterRoleBinding"}: true,
{Group: "scheduling.k8s.io", Kind: "PriorityClass"}: true,
{Group: "storage.k8s.io", Kind: "StorageClass"}: true,
{Group: "storage.k8s.io", Kind: "VolumeAttachment"}: true,
{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"}: true,
{Group: "apiserver.k8s.io", Kind: "AdmissionConfiguration"}: true,
{Group: "audit.k8s.io", Kind: "Event"}: true,
{Group: "audit.k8s.io", Kind: "Policy"}: true,
{Group: "apiregistration.k8s.io", Kind: "APIService"}: true,
{Group: "metrics.k8s.io", Kind: "NodeMetrics"}: true,
{Group: "wardle.k8s.io", Kind: "Fischer"}: true,
}
// hardcoded is good enough for the test we're running
var ignoredKinds = sets.NewString(
"ListOptions",
"DeleteOptions",
"Status",
"PodLogOptions",
"PodExecOptions",
"PodAttachOptions",
"PodPortForwardOptions",
"PodProxyOptions",
"NodeProxyOptions",
"ServiceProxyOptions",
)

View File

@ -1,47 +0,0 @@
/*
Copyright 2016 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 meta
import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// InterfacesForUnstructuredConversion returns VersionInterfaces suitable for
// dealing with unstructured.Unstructured objects and supports conversion
// from typed objects (provided by parent) to untyped objects.
func InterfacesForUnstructuredConversion(parent VersionInterfacesFunc) VersionInterfacesFunc {
return func(version schema.GroupVersion) (*VersionInterfaces, error) {
if i, err := parent(version); err == nil {
return &VersionInterfaces{
ObjectConvertor: i.ObjectConvertor,
MetadataAccessor: NewAccessor(),
}, nil
}
return InterfacesForUnstructured(version)
}
}
// InterfacesForUnstructured returns VersionInterfaces suitable for
// dealing with unstructured.Unstructured objects. It will return errors for
// other conversions.
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
return &VersionInterfaces{
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
MetadataAccessor: NewAccessor(),
}, nil
}

View File

@ -1,69 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"amount_test.go",
"math_test.go",
"quantity_proto_test.go",
"quantity_test.go",
"scale_int_test.go",
],
embed = [":go_default_library"],
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/gopkg.in/inf.v0:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"amount.go",
"generated.pb.go",
"math.go",
"quantity.go",
"quantity_proto.go",
"scale_int.go",
"suffix.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/apimachinery/pkg/api/resource",
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/gopkg.in/inf.v0:go_default_library",
],
)
go_test(
name = "go_default_xtest",
srcs = ["quantity_example_test.go"],
deps = ["//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
filegroup(
name = "go_default_library_protos",
srcs = ["generated.proto"],
visibility = ["//visibility:public"],
)

View File

@ -131,3 +131,32 @@ func TestAmountSign(t *testing.T) {
}
}
}
func TestInt64AmountAsScaledInt64(t *testing.T) {
for _, test := range []struct {
name string
i int64Amount
scaled Scale
result int64
ok bool
}{
{"test when i.scale < scaled ", int64Amount{value: 100, scale: 0}, 5, 1, true},
{"test when i.scale = scaled", int64Amount{value: 100, scale: 1}, 1, 100, true},
{"test when i.scale > scaled and result doesn't overflow", int64Amount{value: 100, scale: 5}, 2, 100000, true},
{"test when i.scale > scaled and result overflows", int64Amount{value: 876, scale: 30}, 4, 0, false},
{"test when i.scale < 0 and fraction exists", int64Amount{value: 93, scale: -1}, 0, 10, true},
{"test when i.scale < 0 and fraction doesn't exist", int64Amount{value: 100, scale: -1}, 0, 10, true},
{"test when i.value < 0 and fraction exists", int64Amount{value: -1932, scale: 2}, 4, -20, true},
{"test when i.value < 0 and fraction doesn't exists", int64Amount{value: -1900, scale: 2}, 4, -19, true},
} {
t.Run(test.name, func(t *testing.T) {
r, ok := test.i.AsScaledInt64(test.scaled)
if r != test.result {
t.Errorf("%v: expected result: %d, got result: %d", test.name, test.result, r)
}
if ok != test.ok {
t.Errorf("%v: expected ok: %t, got ok: %t", test.name, test.ok, ok)
}
})
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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.
@ -14,18 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by protoc-gen-gogo.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
// DO NOT EDIT!
/*
Package resource is a generated protocol buffer package.
Package resource is a generated protocol buffer package.
It is generated from these files:
k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
It is generated from these files:
k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
It has these top-level messages:
Quantity
It has these top-level messages:
Quantity
*/
package resource
@ -57,21 +56,20 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 255 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8f, 0xa1, 0x4e, 0x03, 0x41,
0x10, 0x86, 0x77, 0x0d, 0x29, 0x95, 0x0d, 0x21, 0xa4, 0x62, 0xaf, 0x21, 0x08, 0x0c, 0x3b, 0x02,
0xd3, 0x20, 0xf1, 0x08, 0x90, 0xb8, 0xbb, 0xeb, 0xb0, 0xdd, 0x1c, 0xdd, 0xbd, 0xcc, 0xce, 0x92,
0xd4, 0x55, 0x22, 0x2b, 0x91, 0xbd, 0xb7, 0xa9, 0xac, 0xac, 0x40, 0x70, 0xcb, 0x8b, 0x90, 0x5e,
0xdb, 0x84, 0x90, 0xe0, 0xe6, 0xfb, 0x27, 0xdf, 0xe4, 0x9f, 0xfe, 0x43, 0x35, 0x0e, 0xda, 0x7a,
0xa8, 0x62, 0x81, 0xe4, 0x90, 0x31, 0xc0, 0x1b, 0xba, 0x89, 0x27, 0x38, 0x2c, 0xf2, 0xda, 0xce,
0xf2, 0x72, 0x6a, 0x1d, 0xd2, 0x1c, 0xea, 0xca, 0xec, 0x02, 0x20, 0x0c, 0x3e, 0x52, 0x89, 0x60,
0xd0, 0x21, 0xe5, 0x8c, 0x13, 0x5d, 0x93, 0x67, 0x3f, 0xb8, 0xda, 0x5b, 0xfa, 0xb7, 0xa5, 0xeb,
0xca, 0xec, 0x02, 0x7d, 0xb4, 0x86, 0x37, 0xc6, 0xf2, 0x34, 0x16, 0xba, 0xf4, 0x33, 0x30, 0xde,
0x78, 0xe8, 0xe4, 0x22, 0xbe, 0x74, 0xd4, 0x41, 0x37, 0xed, 0x8f, 0x0e, 0x6f, 0xff, 0xab, 0x12,
0xd9, 0xbe, 0x82, 0x75, 0x1c, 0x98, 0xfe, 0x36, 0xb9, 0x1c, 0xf7, 0x7b, 0x8f, 0x31, 0x77, 0x6c,
0x79, 0x3e, 0x38, 0xef, 0x9f, 0x04, 0x26, 0xeb, 0xcc, 0x85, 0x1c, 0xc9, 0xeb, 0xd3, 0xa7, 0x03,
0xdd, 0x9d, 0x7d, 0xac, 0x32, 0xf1, 0xde, 0x64, 0x62, 0xd9, 0x64, 0x62, 0xd5, 0x64, 0x62, 0xf1,
0x39, 0x12, 0xf7, 0x7a, 0xdd, 0x2a, 0xb1, 0x69, 0x95, 0xd8, 0xb6, 0x4a, 0x2c, 0x92, 0x92, 0xeb,
0xa4, 0xe4, 0x26, 0x29, 0xb9, 0x4d, 0x4a, 0x7e, 0x25, 0x25, 0x97, 0xdf, 0x4a, 0x3c, 0xf7, 0x8e,
0xdf, 0xfc, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x5e, 0xda, 0xf9, 0x43, 0x01, 0x00, 0x00,
// 237 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8e, 0xb1, 0x4e, 0xc3, 0x30,
0x10, 0x40, 0xcf, 0x0b, 0x2a, 0x19, 0x2b, 0x84, 0x10, 0xc3, 0xa5, 0x42, 0x0c, 0x2c, 0xd8, 0x6b,
0xc5, 0xc8, 0xce, 0x00, 0x23, 0x5b, 0x92, 0x1e, 0xae, 0x15, 0xd5, 0x8e, 0x2e, 0x36, 0x52, 0xb7,
0x8e, 0x8c, 0x1d, 0x19, 0x9b, 0xbf, 0xe9, 0xd8, 0xb1, 0x03, 0x03, 0x31, 0x3f, 0x82, 0xea, 0x36,
0x52, 0xb7, 0x7b, 0xef, 0xf4, 0x4e, 0x97, 0xbd, 0xd4, 0xd3, 0x56, 0x1a, 0xa7, 0xea, 0x50, 0x12,
0x5b, 0xf2, 0xd4, 0xaa, 0x4f, 0xb2, 0x33, 0xc7, 0xea, 0xb4, 0x28, 0x1a, 0xb3, 0x28, 0xaa, 0xb9,
0xb1, 0xc4, 0x4b, 0xd5, 0xd4, 0xfa, 0x20, 0x14, 0x53, 0xeb, 0x02, 0x57, 0xa4, 0x34, 0x59, 0xe2,
0xc2, 0xd3, 0x4c, 0x36, 0xec, 0xbc, 0x1b, 0xdf, 0x1f, 0x2b, 0x79, 0x5e, 0xc9, 0xa6, 0xd6, 0x07,
0x21, 0x87, 0xea, 0xf6, 0x51, 0x1b, 0x3f, 0x0f, 0xa5, 0xac, 0xdc, 0x42, 0x69, 0xa7, 0x9d, 0x4a,
0x71, 0x19, 0x3e, 0x12, 0x25, 0x48, 0xd3, 0xf1, 0xe8, 0xdd, 0x34, 0x1b, 0xbd, 0x86, 0xc2, 0x7a,
0xe3, 0x97, 0xe3, 0xeb, 0xec, 0xa2, 0xf5, 0x6c, 0xac, 0xbe, 0x11, 0x13, 0xf1, 0x70, 0xf9, 0x76,
0xa2, 0xa7, 0xab, 0xef, 0x4d, 0x0e, 0x5f, 0x5d, 0x0e, 0xeb, 0x2e, 0x87, 0x4d, 0x97, 0xc3, 0xea,
0x67, 0x02, 0xcf, 0x72, 0xdb, 0x23, 0xec, 0x7a, 0x84, 0x7d, 0x8f, 0xb0, 0x8a, 0x28, 0xb6, 0x11,
0xc5, 0x2e, 0xa2, 0xd8, 0x47, 0x14, 0xbf, 0x11, 0xc5, 0xfa, 0x0f, 0xe1, 0x7d, 0x34, 0x3c, 0xf6,
0x1f, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x08, 0x88, 0x49, 0x0e, 0x01, 0x00, 0x00,
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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.
@ -21,17 +21,15 @@ syntax = 'proto2';
package k8s.io.apimachinery.pkg.api.resource;
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "resource";
// Quantity is a fixed-point representation of a number.
// It provides convenient marshaling/unmarshaling in JSON and YAML,
// in addition to String() and Int64() accessors.
//
//
// The serialization format is:
//
//
// <quantity> ::= <signedNumber><suffix>
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
// <digit> ::= 0 | 1 | ... | 9
@ -45,16 +43,16 @@ option go_package = "resource";
// <decimalSI> ::= m | "" | k | M | G | T | P | E
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
//
//
// No matter which of the three exponent forms is used, no quantity may represent
// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
// places. Numbers larger or more precise will be capped or rounded up.
// (E.g.: 0.1m will rounded up to 1m.)
// This may be extended in the future if we require larger or smaller quantities.
//
//
// When a Quantity is parsed from a string, it will remember the type of suffix
// it had, and will use the same type again when it is serialized.
//
//
// Before serializing, Quantity will be put in "canonical form".
// This means that Exponent/suffix will be adjusted up or down (with a
// corresponding increase or decrease in Mantissa) such that:
@ -62,27 +60,22 @@ option go_package = "resource";
// b. No fractional digits will be emitted
// c. The exponent (or suffix) is as large as possible.
// The sign will be omitted unless the number is negative.
//
//
// Examples:
// 1.5 will be serialized as "1500m"
// 1.5Gi will be serialized as "1536Mi"
//
// NOTE: We reserve the right to amend this canonical format, perhaps to
// allow 1.5 to be canonical.
// TODO: Remove above disclaimer after all bikeshedding about format is over,
// or after March 2015.
//
//
// Note that the quantity will NEVER be internally represented by a
// floating point number. That is the whole point of this exercise.
//
//
// Non-canonical values will still parse as long as they are well formed,
// but will be re-emitted in their canonical form. (So always use canonical
// form, or don't diff.)
//
//
// This format is intended to make it difficult to use these numbers without
// writing some sort of special handling code in the hopes that that will
// cause implementors to also use a fixed point implementation.
//
//
// +protobuf=true
// +protobuf.embed=string
// +protobuf.options.marshal=false

View File

@ -21,12 +21,9 @@ import (
"errors"
"fmt"
"math/big"
"regexp"
"strconv"
"strings"
flag "github.com/spf13/pflag"
inf "gopkg.in/inf.v0"
)
@ -71,11 +68,6 @@ import (
// 1.5 will be serialized as "1500m"
// 1.5Gi will be serialized as "1536Mi"
//
// NOTE: We reserve the right to amend this canonical format, perhaps to
// allow 1.5 to be canonical.
// TODO: Remove above disclaimer after all bikeshedding about format is over,
// or after March 2015.
//
// Note that the quantity will NEVER be internally represented by a
// floating point number. That is the whole point of this exercise.
//
@ -144,9 +136,6 @@ const (
)
var (
// splitRE is used to get the various parts of a number.
splitRE = regexp.MustCompile(splitREString)
// Errors that could happen while parsing a string.
ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'")
ErrNumeric = errors.New("unable to parse numeric part of quantity")
@ -508,7 +497,7 @@ func (q *Quantity) Sign() int {
return q.i.Sign()
}
// AsScaled returns the current value, rounded up to the provided scale, and returns
// AsScale returns the current value, rounded up to the provided scale, and returns
// false if the scale resulted in a loss of precision.
func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
if q.d.Dec != nil {
@ -747,43 +736,3 @@ func (q *Quantity) Copy() *Quantity {
Format: q.Format,
}
}
// qFlag is a helper type for the Flag function
type qFlag struct {
dest *Quantity
}
// Sets the value of the internal Quantity. (used by flag & pflag)
func (qf qFlag) Set(val string) error {
q, err := ParseQuantity(val)
if err != nil {
return err
}
// This copy is OK because q will not be referenced again.
*qf.dest = q
return nil
}
// Converts the value of the internal Quantity to a string. (used by flag & pflag)
func (qf qFlag) String() string {
return qf.dest.String()
}
// States the type of flag this is (Quantity). (used by pflag)
func (qf qFlag) Type() string {
return "quantity"
}
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
// Will panic if defaultValue is not a valid quantity.
func QuantityFlag(flagName, defaultValue, description string) *Quantity {
q := MustParse(defaultValue)
flag.Var(NewQuantityFlagValue(&q), flagName, description)
return &q
}
// NewQuantityFlagValue returns an object that can be used to back a flag,
// pointing at the given Quantity variable.
func NewQuantityFlagValue(q *Quantity) flag.Value {
return qFlag{q}
}

View File

@ -24,7 +24,6 @@ import (
"unicode"
fuzz "github.com/google/gofuzz"
"github.com/spf13/pflag"
inf "gopkg.in/inf.v0"
)
@ -1059,21 +1058,6 @@ func TestCopy(t *testing.T) {
}
}
func TestQFlagSet(t *testing.T) {
qf := qFlag{&Quantity{}}
qf.Set("1Ki")
if e, a := "1Ki", qf.String(); e != a {
t.Errorf("Unexpected result %v != %v", e, a)
}
}
func TestQFlagIsPFlag(t *testing.T) {
var pfv pflag.Value = qFlag{}
if e, a := "quantity", pfv.Type(); e != a {
t.Errorf("Unexpected result %v != %v", e, a)
}
}
func TestSub(t *testing.T) {
tests := []struct {
a Quantity

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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,35 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["codec.go"],
importpath = "k8s.io/apimachinery/pkg/api/testing",
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/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/testing/fuzzer:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/testing/roundtrip:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -1,86 +0,0 @@
/*
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 testing
import (
"fmt"
"mime"
"os"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
)
var (
testCodecMediaType string
testStorageCodecMediaType string
)
// TestCodec returns the codec for the API version to test against, as set by the
// KUBE_TEST_API_TYPE env var.
func TestCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
if len(testCodecMediaType) != 0 {
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testCodecMediaType)
if !ok {
panic(fmt.Sprintf("no serializer for %s", testCodecMediaType))
}
return codecs.CodecForVersions(serializerInfo.Serializer, codecs.UniversalDeserializer(), schema.GroupVersions(gvs), nil)
}
return codecs.LegacyCodec(gvs...)
}
// TestStorageCodec returns the codec for the API version to test against used in storage, as set by the
// KUBE_TEST_API_STORAGE_TYPE env var.
func TestStorageCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
if len(testStorageCodecMediaType) != 0 {
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testStorageCodecMediaType)
if !ok {
panic(fmt.Sprintf("no serializer for %s", testStorageCodecMediaType))
}
// etcd2 only supports string data - we must wrap any result before returning
// TODO: remove for etcd3 / make parameterizable
serializer := serializerInfo.Serializer
if !serializerInfo.EncodesAsText {
serializer = runtime.NewBase64Serializer(serializer, serializer)
}
decoder := recognizer.NewDecoder(serializer, codecs.UniversalDeserializer())
return codecs.CodecForVersions(serializer, decoder, schema.GroupVersions(gvs), nil)
}
return codecs.LegacyCodec(gvs...)
}
func init() {
var err error
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
testCodecMediaType, _, err = mime.ParseMediaType(apiMediaType)
if err != nil {
panic(err)
}
}
if storageMediaType := os.Getenv("KUBE_TEST_API_STORAGE_TYPE"); len(storageMediaType) > 0 {
testStorageCodecMediaType, _, err = mime.ParseMediaType(storageMediaType)
if err != nil {
panic(err)
}
}
}

View File

@ -1,39 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["valuefuzz_test.go"],
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"fuzzer.go",
"valuefuzz.go",
],
importpath = "k8s.io/apimachinery/pkg/api/testing/fuzzer",
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,45 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["roundtrip.go"],
importpath = "k8s.io/apimachinery/pkg/api/testing/roundtrip",
deps = [
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/golang/protobuf/proto:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer: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/serializer/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,403 +0,0 @@
/*
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 roundtrip
import (
"bytes"
"encoding/hex"
"math/rand"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/golang/protobuf/proto"
"github.com/google/gofuzz"
flag "github.com/spf13/pflag"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apimeta "k8s.io/apimachinery/pkg/api/meta"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets"
)
type InstallFunc func(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme)
// RoundTripTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
// enough information to round trip
func RoundTripTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
registry := registered.NewOrDie("")
scheme := runtime.NewScheme()
installFn(groupFactoryRegistry, registry, scheme)
RoundTripTestForScheme(t, scheme, fuzzingFuncs)
}
// RoundTripTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
func RoundTripTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
codecFactory := runtimeserializer.NewCodecFactory(scheme)
f := fuzzer.FuzzerFor(
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
rand.NewSource(rand.Int63()),
codecFactory,
)
RoundTripTypesWithoutProtobuf(t, scheme, codecFactory, f, nil)
}
// RoundTripProtobufTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
// enough information to round trip
func RoundTripProtobufTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
registry := registered.NewOrDie("")
scheme := runtime.NewScheme()
installFn(groupFactoryRegistry, registry, scheme)
RoundTripProtobufTestForScheme(t, scheme, fuzzingFuncs)
}
// RoundTripProtobufTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
func RoundTripProtobufTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
codecFactory := runtimeserializer.NewCodecFactory(scheme)
fuzzer := fuzzer.FuzzerFor(
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
rand.NewSource(rand.Int63()),
codecFactory,
)
RoundTripTypes(t, scheme, codecFactory, fuzzer, nil)
}
var FuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
// globalNonRoundTrippableTypes are kinds that are effectively reserved across all GroupVersions
// They don't roundtrip
var globalNonRoundTrippableTypes = sets.NewString(
"ExportOptions",
"GetOptions",
// WatchEvent does not include kind and version and can only be deserialized
// implicitly (if the caller expects the specific object). The watch call defines
// the schema by content type, rather than via kind/version included in each
// object.
"WatchEvent",
// ListOptions is now part of the meta group
"ListOptions",
// Delete options is only read in metav1
"DeleteOptions",
)
// RoundTripTypesWithoutProtobuf applies the round-trip test to all round-trippable Kinds
// in the scheme. It will skip all the GroupVersionKinds in the skip list.
func RoundTripTypesWithoutProtobuf(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
}
func RoundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
}
func roundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
for _, group := range groupsFromScheme(scheme) {
t.Logf("starting group %q", group)
internalVersion := schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal}
internalKindToGoType := scheme.KnownTypes(internalVersion)
for kind := range internalKindToGoType {
if globalNonRoundTrippableTypes.Has(kind) {
continue
}
internalGVK := internalVersion.WithKind(kind)
roundTripSpecificKind(t, internalGVK, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, skipProtobuf)
}
t.Logf("finished group %q", group)
}
}
func RoundTripSpecificKindWithoutProtobuf(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
}
func RoundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
}
func roundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
if nonRoundTrippableTypes[gvk] {
t.Logf("skipping %v", gvk)
return
}
t.Logf("round tripping %v", gvk)
// Try a few times, since runTest uses random values.
for i := 0; i < *FuzzIters; i++ {
if gvk.Version == runtime.APIVersionInternal {
roundTripToAllExternalVersions(t, scheme, codecFactory, fuzzer, gvk, nonRoundTrippableTypes, skipProtobuf)
} else {
roundTripOfExternalType(t, scheme, codecFactory, fuzzer, gvk, skipProtobuf)
}
if t.Failed() {
break
}
}
}
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
// fuzzer registered with the apitesting package.
func fuzzInternalObject(t *testing.T, fuzzer *fuzz.Fuzzer, object runtime.Object) runtime.Object {
fuzzer.Fuzz(object)
j, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("Unexpected error %v for %#v", err, object)
}
j.SetKind("")
j.SetAPIVersion("")
return object
}
func groupsFromScheme(scheme *runtime.Scheme) []string {
ret := sets.String{}
for gvk := range scheme.AllKnownTypes() {
ret.Insert(gvk.Group)
}
return ret.List()
}
func roundTripToAllExternalVersions(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, internalGVK schema.GroupVersionKind, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
object, err := scheme.New(internalGVK)
if err != nil {
t.Fatalf("Couldn't make a %v? %v", internalGVK, err)
}
if _, err := apimeta.TypeAccessor(object); err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", internalGVK, err)
}
fuzzInternalObject(t, fuzzer, object)
// find all potential serializations in the scheme.
// TODO fix this up to handle kinds that cross registered with different names.
for externalGVK, externalGoType := range scheme.AllKnownTypes() {
if externalGVK.Version == runtime.APIVersionInternal {
continue
}
if externalGVK.GroupKind() != internalGVK.GroupKind() {
continue
}
if nonRoundTrippableTypes[externalGVK] {
t.Logf("\tskipping %v %v", externalGVK, externalGoType)
continue
}
t.Logf("\tround tripping to %v %v", externalGVK, externalGoType)
roundTrip(t, scheme, apitesting.TestCodec(codecFactory, externalGVK.GroupVersion()), object)
// TODO remove this hack after we're past the intermediate steps
if !skipProtobuf && externalGVK.Group != "kubeadm.k8s.io" {
s := protobuf.NewSerializer(scheme, scheme, "application/arbitrary.content.type")
protobufCodec := codecFactory.CodecForVersions(s, s, externalGVK.GroupVersion(), nil)
roundTrip(t, scheme, protobufCodec, object)
}
}
}
func roundTripOfExternalType(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, externalGVK schema.GroupVersionKind, skipProtobuf bool) {
object, err := scheme.New(externalGVK)
if err != nil {
t.Fatalf("Couldn't make a %v? %v", externalGVK, err)
}
typeAcc, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", externalGVK, err)
}
fuzzInternalObject(t, fuzzer, object)
externalGoType := reflect.TypeOf(object).PkgPath()
t.Logf("\tround tripping external type %v %v", externalGVK, externalGoType)
typeAcc.SetKind(externalGVK.Kind)
typeAcc.SetAPIVersion(externalGVK.GroupVersion().String())
roundTrip(t, scheme, json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false), object)
// TODO remove this hack after we're past the intermediate steps
if !skipProtobuf {
roundTrip(t, scheme, protobuf.NewSerializer(scheme, scheme, "application/protobuf"), object)
}
}
// roundTrip applies a single round-trip test to the given runtime object
// using the given codec. The round-trip test ensures that an object can be
// deep-copied, converted, marshaled and back without loss of data.
//
// For internal types this means
//
// internal -> external -> json/protobuf -> external -> internal.
//
// For external types this means
//
// external -> json/protobuf -> external.
func roundTrip(t *testing.T, scheme *runtime.Scheme, codec runtime.Codec, object runtime.Object) {
printer := spew.ConfigState{DisableMethods: true}
original := object
// deep copy the original object
object = object.DeepCopyObject()
name := reflect.TypeOf(object).Elem().Name()
if !apiequality.Semantic.DeepEqual(original, object) {
t.Errorf("%v: DeepCopy altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
t.Errorf("%s", spew.Sdump(original))
t.Errorf("%s", spew.Sdump(object))
return
}
// encode (serialize) the deep copy using the provided codec
data, err := runtime.Encode(codec, object)
if err != nil {
if runtime.IsNotRegisteredError(err) {
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
} else {
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
}
return
}
// ensure that the deep copy is equal to the original; neither the deep
// copy or conversion should alter the object
// TODO eliminate this global
if !apiequality.Semantic.DeepEqual(original, object) {
t.Errorf("%v: encode altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
return
}
// encode (serialize) a second time to verify that it was not varying
secondData, err := runtime.Encode(codec, object)
if err != nil {
if runtime.IsNotRegisteredError(err) {
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
} else {
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
}
return
}
// serialization to the wire must be stable to ensure that we don't write twice to the DB
// when the object hasn't changed.
if !bytes.Equal(data, secondData) {
t.Errorf("%v: serialization is not stable: %s", name, printer.Sprintf("%#v", object))
}
// decode (deserialize) the encoded data back into an object
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Errorf("%v: %v\nCodec: %#v\nData: %s\nSource: %#v", name, err, codec, dataAsString(data), printer.Sprintf("%#v", object))
panic("failed")
}
// ensure that the object produced from decoding the encoded data is equal
// to the original object
if !apiequality.Semantic.DeepEqual(original, obj2) {
t.Errorf("%v: diff: %v\nCodec: %#v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, diff.ObjectReflectDiff(original, obj2), codec, printer.Sprintf("%#v", original), dataAsString(data), printer.Sprintf("%#v", obj2))
return
}
// decode the encoded data into a new object (instead of letting the codec
// create a new object)
obj3 := reflect.New(reflect.TypeOf(object).Elem()).Interface().(runtime.Object)
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Errorf("%v: %v", name, err)
return
}
// special case for kinds which are internal and external at the same time (many in meta.k8s.io are). For those
// runtime.DecodeInto above will return the external variant and set the APIVersion and kind, while the input
// object might be internal. Hence, we clear those values for obj3 for that case to correctly compare.
intAndExt, err := internalAndExternalKind(scheme, object)
if err != nil {
t.Errorf("%v: %v", name, err)
return
}
if intAndExt {
typeAcc, err := apimeta.TypeAccessor(object)
if err != nil {
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
}
if len(typeAcc.GetAPIVersion()) == 0 {
typeAcc, err := apimeta.TypeAccessor(obj3)
if err != nil {
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
}
typeAcc.SetAPIVersion("")
typeAcc.SetKind("")
}
}
// ensure that the new runtime object is equal to the original after being
// decoded into
if !apiequality.Semantic.DeepEqual(object, obj3) {
t.Errorf("%v: diff: %v\nCodec: %#v", name, diff.ObjectReflectDiff(object, obj3), codec)
return
}
// do structure-preserving fuzzing of the deep-copied object. If it shares anything with the original,
// the deep-copy was actually only a shallow copy. Then original and obj3 will be different after fuzzing.
// NOTE: we use the encoding+decoding here as an alternative, guaranteed deep-copy to compare against.
fuzzer.ValueFuzz(object)
if !apiequality.Semantic.DeepEqual(original, obj3) {
t.Errorf("%v: fuzzing a copy altered the original, diff: %v", name, diff.ObjectReflectDiff(original, obj3))
return
}
}
func internalAndExternalKind(scheme *runtime.Scheme, object runtime.Object) (bool, error) {
kinds, _, err := scheme.ObjectKinds(object)
if err != nil {
return false, err
}
internal, external := false, false
for _, k := range kinds {
if k.Version == runtime.APIVersionInternal {
internal = true
} else {
external = true
}
}
return internal && external, nil
}
// dataAsString returns the given byte array as a string; handles detecting
// protocol buffers.
func dataAsString(data []byte) string {
dataString := string(data)
if !strings.HasPrefix(dataString, "{") {
dataString = "\n" + hex.Dump(data)
proto.NewBuffer(make([]byte, 0, 1024)).DebugPrint("decoded object", data)
}
return dataString
}

View File

@ -1,53 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["objectmeta_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"generic.go",
"objectmeta.go",
],
importpath = "k8s.io/apimachinery/pkg/api/validation",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/validation/path:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -30,10 +30,6 @@ import (
"k8s.io/apimachinery/pkg/util/validation/field"
)
// TODO: delete this global variable when we enable the validation of common
// fields by default.
var RepairMalformedUpdates bool = true
const FieldImmutableErrorMsg string = `field is immutable`
const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
@ -254,39 +250,6 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *fiel
func ValidateObjectMetaAccessorUpdate(newMeta, oldMeta metav1.Object, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
if !RepairMalformedUpdates && newMeta.GetUID() != oldMeta.GetUID() {
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), newMeta.GetUID(), "field is immutable"))
}
// in the event it is left empty, set it, to allow clients more flexibility
// TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
// Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
if RepairMalformedUpdates {
if len(newMeta.GetUID()) == 0 {
newMeta.SetUID(oldMeta.GetUID())
}
// ignore changes to timestamp
if oldCreationTime := oldMeta.GetCreationTimestamp(); oldCreationTime.IsZero() {
oldMeta.SetCreationTimestamp(newMeta.GetCreationTimestamp())
} else {
newMeta.SetCreationTimestamp(oldMeta.GetCreationTimestamp())
}
// an object can never remove a deletion timestamp or clear/change grace period seconds
if !oldMeta.GetDeletionTimestamp().IsZero() {
newMeta.SetDeletionTimestamp(oldMeta.GetDeletionTimestamp())
}
if oldMeta.GetDeletionGracePeriodSeconds() != nil && newMeta.GetDeletionGracePeriodSeconds() == nil {
newMeta.SetDeletionGracePeriodSeconds(oldMeta.GetDeletionGracePeriodSeconds())
}
}
// TODO: needs to check if newMeta==nil && oldMeta !=nil after the repair logic is removed.
if newMeta.GetDeletionGracePeriodSeconds() != nil && (oldMeta.GetDeletionGracePeriodSeconds() == nil || *newMeta.GetDeletionGracePeriodSeconds() != *oldMeta.GetDeletionGracePeriodSeconds()) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionGracePeriodSeconds"), newMeta.GetDeletionGracePeriodSeconds(), "field is immutable; may only be changed via deletion"))
}
if newMeta.GetDeletionTimestamp() != nil && (oldMeta.GetDeletionTimestamp() == nil || !newMeta.GetDeletionTimestamp().Equal(oldMeta.GetDeletionTimestamp())) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionTimestamp"), newMeta.GetDeletionTimestamp(), "field is immutable; may only be changed via deletion"))
}
// Finalizers cannot be added if the object is already being deleted.
if oldMeta.GetDeletionTimestamp() != nil {
allErrs = append(allErrs, ValidateNoNewFinalizers(newMeta.GetFinalizers(), oldMeta.GetFinalizers(), fldPath.Child("finalizers"))...)
@ -308,6 +271,8 @@ func ValidateObjectMetaAccessorUpdate(newMeta, oldMeta metav1.Object, fldPath *f
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetNamespace(), oldMeta.GetNamespace(), fldPath.Child("namespace"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetUID(), oldMeta.GetUID(), fldPath.Child("uid"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetCreationTimestamp(), oldMeta.GetCreationTimestamp(), fldPath.Child("creationTimestamp"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionTimestamp(), oldMeta.GetDeletionTimestamp(), fldPath.Child("deletionTimestamp"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionGracePeriodSeconds(), oldMeta.GetDeletionGracePeriodSeconds(), fldPath.Child("deletionGracePeriodSeconds"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetClusterName(), oldMeta.GetClusterName(), fldPath.Child("clusterName"))...)
allErrs = append(allErrs, v1validation.ValidateLabels(newMeta.GetLabels(), fldPath.Child("labels"))...)

View File

@ -219,21 +219,21 @@ func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) {
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
field.NewPath("field"),
); len(errs) != 0 {
); len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs)
}
if errs := ValidateObjectMetaUpdate(
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
field.NewPath("field"),
); len(errs) != 0 {
); len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs)
}
if errs := ValidateObjectMetaUpdate(
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(11, 0))},
field.NewPath("field"),
); len(errs) != 0 {
); len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs)
}
}
@ -328,38 +328,38 @@ func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable; may only be changed via deletion"},
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable"},
},
"invalid clear deletionTimestamp": {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
ExpectedErrs: []string{}, // no errors, validation copies the old value
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: \"null\": field is immutable"},
},
"invalid change deletionTimestamp": {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
ExpectedErrs: []string{}, // no errors, validation copies the old value
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later},
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:33:20 +0000 UTC: field is immutable"},
},
"invalid set deletionGracePeriodSeconds": {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 30: field is immutable; may only be changed via deletion"},
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 30: field is immutable"},
},
"invalid clear deletionGracePeriodSeconds": {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
ExpectedErrs: []string{}, // no errors, validation copies the old value
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: \"null\": field is immutable"},
},
"invalid change deletionGracePeriodSeconds": {
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 40: field is immutable; may only be changed via deletion"},
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 40: field is immutable"},
},
}

View File

@ -1,32 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["name_test.go"],
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["name.go"],
importpath = "k8s.io/apimachinery/pkg/api/validation/path",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,45 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["types_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"types.go",
],
importpath = "k8s.io/apimachinery/pkg/apimachinery",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/apimachinery/announced:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/apimachinery/registered:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -1,45 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["announced_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"announced.go",
"group_factory.go",
],
importpath = "k8s.io/apimachinery/pkg/apimachinery/announced",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered: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/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,99 +0,0 @@
/*
Copyright 2016 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 announced contains tools for announcing API group factories. This is
// distinct from registration (in the 'registered' package) in that it's safe
// to announce every possible group linked in, but only groups requested at
// runtime should be registered. This package contains both a registry, and
// factory code (which was formerly copy-pasta in every install package).
package announced
import (
"fmt"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
)
// APIGroupFactoryRegistry allows for groups and versions to announce themselves,
// which simply makes them available and doesn't take other actions. Later,
// users of the registry can select which groups and versions they'd actually
// like to register with an APIRegistrationManager.
//
// (Right now APIRegistrationManager has separate 'registration' and 'enabled'
// concepts-- APIGroupFactory is going to take over the former function;
// they will overlap until the refactoring is finished.)
//
// The key is the group name. After initialization, this should be treated as
// read-only. It is implemented as a map from group name to group factory, and
// it is safe to use this knowledge to manually pick out groups to register
// (e.g., for testing).
type APIGroupFactoryRegistry map[string]*GroupMetaFactory
func (gar APIGroupFactoryRegistry) group(groupName string) *GroupMetaFactory {
gmf, ok := gar[groupName]
if !ok {
gmf = &GroupMetaFactory{VersionArgs: map[string]*GroupVersionFactoryArgs{}}
gar[groupName] = gmf
}
return gmf
}
// AnnounceGroupVersion adds the particular arguments for this group version to the group factory.
func (gar APIGroupFactoryRegistry) AnnounceGroupVersion(gvf *GroupVersionFactoryArgs) error {
gmf := gar.group(gvf.GroupName)
if _, ok := gmf.VersionArgs[gvf.VersionName]; ok {
return fmt.Errorf("version %q in group %q has already been announced", gvf.VersionName, gvf.GroupName)
}
gmf.VersionArgs[gvf.VersionName] = gvf
return nil
}
// AnnounceGroup adds the group-wide arguments to the group factory.
func (gar APIGroupFactoryRegistry) AnnounceGroup(args *GroupMetaFactoryArgs) error {
gmf := gar.group(args.GroupName)
if gmf.GroupArgs != nil {
return fmt.Errorf("group %q has already been announced", args.GroupName)
}
gmf.GroupArgs = args
return nil
}
// RegisterAndEnableAll throws every factory at the specified API registration
// manager, and lets it decide which to register. (If you want to do this a la
// cart, you may look through gar itself-- it's just a map.)
func (gar APIGroupFactoryRegistry) RegisterAndEnableAll(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
for groupName, gmf := range gar {
if err := gmf.Register(m); err != nil {
return fmt.Errorf("error registering %v: %v", groupName, err)
}
if err := gmf.Enable(m, scheme); err != nil {
return fmt.Errorf("error enabling %v: %v", groupName, err)
}
}
return nil
}
// AnnouncePreconstructedFactory announces a factory which you've manually assembled.
// You may call this instead of calling AnnounceGroup and AnnounceGroupVersion.
func (gar APIGroupFactoryRegistry) AnnouncePreconstructedFactory(gmf *GroupMetaFactory) error {
name := gmf.GroupArgs.GroupName
if _, exists := gar[name]; exists {
return fmt.Errorf("the group %q has already been announced.", name)
}
gar[name] = gmf
return nil
}

View File

@ -1,64 +0,0 @@
/*
Copyright 2016 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 announced
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/sets"
)
func TestFactoryRegistry(t *testing.T) {
regA := make(APIGroupFactoryRegistry)
regB := make(APIGroupFactoryRegistry)
if err := regA.AnnounceGroup(&GroupMetaFactoryArgs{
GroupName: "foo",
VersionPreferenceOrder: []string{"v2", "v1"},
RootScopedKinds: sets.NewString("namespaces"),
}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
GroupName: "foo",
VersionName: "v1",
}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
GroupName: "foo",
VersionName: "v2",
}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if err := regB.AnnouncePreconstructedFactory(NewGroupMetaFactory(
&GroupMetaFactoryArgs{
GroupName: "foo",
VersionPreferenceOrder: []string{"v2", "v1"},
RootScopedKinds: sets.NewString("namespaces"),
},
VersionToSchemeFunc{"v1": nil, "v2": nil},
)); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(regA, regB) {
t.Errorf("Expected both ways of registering to be equivalent, but they were not.\n\n%#v\n\n%#v\n", regA, regB)
}
}

View File

@ -1,255 +0,0 @@
/*
Copyright 2016 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 announced
import (
"fmt"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
type SchemeFunc func(*runtime.Scheme) error
type VersionToSchemeFunc map[string]SchemeFunc
// GroupVersionFactoryArgs contains all the per-version parts of a GroupMetaFactory.
type GroupVersionFactoryArgs struct {
GroupName string
VersionName string
AddToScheme SchemeFunc
}
// GroupMetaFactoryArgs contains the group-level args of a GroupMetaFactory.
type GroupMetaFactoryArgs struct {
// GroupName is the name of the API-Group
//
// example: 'servicecatalog.k8s.io'
GroupName string
VersionPreferenceOrder []string
// RootScopedKinds are resources that are not namespaced.
RootScopedKinds sets.String // nil is allowed
IgnoredKinds sets.String // nil is allowed
// May be nil if there are no internal objects.
AddInternalObjectsToScheme SchemeFunc
}
// NewGroupMetaFactory builds the args for you. This is for if you're
// constructing a factory all at once and not using the registry.
func NewGroupMetaFactory(groupArgs *GroupMetaFactoryArgs, versions VersionToSchemeFunc) *GroupMetaFactory {
gmf := &GroupMetaFactory{
GroupArgs: groupArgs,
VersionArgs: map[string]*GroupVersionFactoryArgs{},
}
for v, f := range versions {
gmf.VersionArgs[v] = &GroupVersionFactoryArgs{
GroupName: groupArgs.GroupName,
VersionName: v,
AddToScheme: f,
}
}
return gmf
}
// Announce adds this Group factory to the global factory registry. It should
// only be called if you constructed the GroupMetaFactory yourself via
// NewGroupMetaFactory.
// Note that this will panic on an error, since it's expected that you'll be
// calling this at initialization time and any error is a result of a
// programmer importing the wrong set of packages. If this assumption doesn't
// work for you, just call DefaultGroupFactoryRegistry.AnnouncePreconstructedFactory
// yourself.
func (gmf *GroupMetaFactory) Announce(groupFactoryRegistry APIGroupFactoryRegistry) *GroupMetaFactory {
if err := groupFactoryRegistry.AnnouncePreconstructedFactory(gmf); err != nil {
panic(err)
}
return gmf
}
// GroupMetaFactory has the logic for actually assembling and registering a group.
//
// There are two ways of obtaining one of these.
// 1. You can announce your group and versions separately, and then let the
// GroupFactoryRegistry assemble this object for you. (This allows group and
// versions to be imported separately, without referencing each other, to
// keep import trees small.)
// 2. You can call NewGroupMetaFactory(), which is mostly a drop-in replacement
// for the old, bad way of doing things. You can then call .Announce() to
// announce your constructed factory to any code that would like to do
// things the new, better way.
//
// Note that GroupMetaFactory actually does construct GroupMeta objects, but
// currently it does so in a way that's very entangled with an
// APIRegistrationManager. It's a TODO item to cleanly separate that interface.
type GroupMetaFactory struct {
GroupArgs *GroupMetaFactoryArgs
// map of version name to version factory
VersionArgs map[string]*GroupVersionFactoryArgs
// assembled by Register()
prioritizedVersionList []schema.GroupVersion
}
// Register constructs the finalized prioritized version list and sanity checks
// the announced group & versions. Then it calls register.
func (gmf *GroupMetaFactory) Register(m *registered.APIRegistrationManager) error {
if gmf.GroupArgs == nil {
return fmt.Errorf("partially announced groups are not allowed, only got versions: %#v", gmf.VersionArgs)
}
if len(gmf.VersionArgs) == 0 {
return fmt.Errorf("group %v announced but no versions announced", gmf.GroupArgs.GroupName)
}
pvSet := sets.NewString(gmf.GroupArgs.VersionPreferenceOrder...)
if pvSet.Len() != len(gmf.GroupArgs.VersionPreferenceOrder) {
return fmt.Errorf("preference order for group %v has duplicates: %v", gmf.GroupArgs.GroupName, gmf.GroupArgs.VersionPreferenceOrder)
}
prioritizedVersions := []schema.GroupVersion{}
for _, v := range gmf.GroupArgs.VersionPreferenceOrder {
prioritizedVersions = append(
prioritizedVersions,
schema.GroupVersion{
Group: gmf.GroupArgs.GroupName,
Version: v,
},
)
}
// Go through versions that weren't explicitly prioritized.
unprioritizedVersions := []schema.GroupVersion{}
for _, v := range gmf.VersionArgs {
if v.GroupName != gmf.GroupArgs.GroupName {
return fmt.Errorf("found %v/%v in group %v?", v.GroupName, v.VersionName, gmf.GroupArgs.GroupName)
}
if pvSet.Has(v.VersionName) {
pvSet.Delete(v.VersionName)
continue
}
unprioritizedVersions = append(unprioritizedVersions, schema.GroupVersion{Group: v.GroupName, Version: v.VersionName})
}
if len(unprioritizedVersions) > 1 {
glog.Warningf("group %v has multiple unprioritized versions: %#v. They will have an arbitrary preference order!", gmf.GroupArgs.GroupName, unprioritizedVersions)
}
if pvSet.Len() != 0 {
return fmt.Errorf("group %v has versions in the priority list that were never announced: %s", gmf.GroupArgs.GroupName, pvSet)
}
prioritizedVersions = append(prioritizedVersions, unprioritizedVersions...)
m.RegisterVersions(prioritizedVersions)
gmf.prioritizedVersionList = prioritizedVersions
return nil
}
func (gmf *GroupMetaFactory) newRESTMapper(scheme *runtime.Scheme, externalVersions []schema.GroupVersion, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := sets.NewString()
if gmf.GroupArgs.RootScopedKinds != nil {
rootScoped = gmf.GroupArgs.RootScopedKinds
}
ignoredKinds := sets.NewString()
if gmf.GroupArgs.IgnoredKinds != nil {
ignoredKinds = gmf.GroupArgs.IgnoredKinds
}
mapper := meta.NewDefaultRESTMapper(externalVersions, groupMeta.InterfacesFor)
for _, gv := range externalVersions {
for kind := range scheme.KnownTypes(gv) {
if ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if rootScoped.Has(kind) {
scope = meta.RESTScopeRoot
}
mapper.Add(gv.WithKind(kind), scope)
}
}
return mapper
}
// Enable enables group versions that are allowed, adds methods to the scheme, etc.
func (gmf *GroupMetaFactory) Enable(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
externalVersions := []schema.GroupVersion{}
for _, v := range gmf.prioritizedVersionList {
if !m.IsAllowedVersion(v) {
continue
}
externalVersions = append(externalVersions, v)
if err := m.EnableVersions(v); err != nil {
return err
}
gmf.VersionArgs[v.Version].AddToScheme(scheme)
}
if len(externalVersions) == 0 {
glog.V(4).Infof("No version is registered for group %v", gmf.GroupArgs.GroupName)
return nil
}
if gmf.GroupArgs.AddInternalObjectsToScheme != nil {
gmf.GroupArgs.AddInternalObjectsToScheme(scheme)
}
preferredExternalVersion := externalVersions[0]
accessor := meta.NewAccessor()
groupMeta := &apimachinery.GroupMeta{
GroupVersion: preferredExternalVersion,
GroupVersions: externalVersions,
SelfLinker: runtime.SelfLinker(accessor),
}
for _, v := range externalVersions {
gvf := gmf.VersionArgs[v.Version]
if err := groupMeta.AddVersionInterfaces(
schema.GroupVersion{Group: gvf.GroupName, Version: gvf.VersionName},
&meta.VersionInterfaces{
ObjectConvertor: scheme,
MetadataAccessor: accessor,
},
); err != nil {
return err
}
}
groupMeta.InterfacesFor = groupMeta.DefaultInterfacesFor
groupMeta.RESTMapper = gmf.newRESTMapper(scheme, externalVersions, groupMeta)
if err := m.RegisterGroup(*groupMeta); err != nil {
return err
}
return nil
}
// RegisterAndEnable is provided only to allow this code to get added in multiple steps.
// It's really bad that this is called in init() methods, but supporting this
// temporarily lets us do the change incrementally.
func (gmf *GroupMetaFactory) RegisterAndEnable(registry *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
if err := gmf.Register(registry); err != nil {
return err
}
if err := gmf.Enable(registry, scheme); err != nil {
return err
}
return nil
}

View File

@ -1,20 +0,0 @@
/*
Copyright 2014 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 apimachinery contains the generic API machinery code that
// is common to both server and clients.
// This package should never import specific API objects.
package apimachinery // import "k8s.io/apimachinery/pkg/apimachinery"

View File

@ -1,43 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["registered_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["registered.go"],
importpath = "k8s.io/apimachinery/pkg/apimachinery/registered",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -1,336 +0,0 @@
/*
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.
*/
// Package to keep track of API Versions that can be registered and are enabled in a Scheme.
package registered
import (
"fmt"
"sort"
"strings"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
// APIRegistrationManager provides the concept of what API groups are enabled.
//
// TODO: currently, it also provides a "registered" concept. But it's wrong to
// have both concepts in the same object. Therefore the "announced" package is
// going to take over the registered concept. After all the install packages
// are switched to using the announce package instead of this package, then we
// can combine the registered/enabled concepts in this object. Simplifying this
// isn't easy right now because there are so many callers of this package.
type APIRegistrationManager struct {
// registeredGroupVersions stores all API group versions for which RegisterGroup is called.
registeredVersions map[schema.GroupVersion]struct{}
// enabledVersions represents all enabled API versions. It should be a
// subset of registeredVersions. Please call EnableVersions() to add
// enabled versions.
enabledVersions map[schema.GroupVersion]struct{}
// map of group meta for all groups.
groupMetaMap map[string]*apimachinery.GroupMeta
// envRequestedVersions represents the versions requested via the
// KUBE_API_VERSIONS environment variable. The install package of each group
// checks this list before add their versions to the latest package and
// Scheme. This list is small and order matters, so represent as a slice
envRequestedVersions []schema.GroupVersion
}
// NewAPIRegistrationManager constructs a new manager. The argument ought to be
// the value of the KUBE_API_VERSIONS env var, or a value of this which you
// wish to test.
func NewAPIRegistrationManager(kubeAPIVersions string) (*APIRegistrationManager, error) {
m := &APIRegistrationManager{
registeredVersions: map[schema.GroupVersion]struct{}{},
enabledVersions: map[schema.GroupVersion]struct{}{},
groupMetaMap: map[string]*apimachinery.GroupMeta{},
envRequestedVersions: []schema.GroupVersion{},
}
if len(kubeAPIVersions) != 0 {
for _, version := range strings.Split(kubeAPIVersions, ",") {
gv, err := schema.ParseGroupVersion(version)
if err != nil {
return nil, fmt.Errorf("invalid api version: %s in KUBE_API_VERSIONS: %s.",
version, kubeAPIVersions)
}
m.envRequestedVersions = append(m.envRequestedVersions, gv)
}
}
return m, nil
}
func NewOrDie(kubeAPIVersions string) *APIRegistrationManager {
m, err := NewAPIRegistrationManager(kubeAPIVersions)
if err != nil {
glog.Fatalf("Could not construct version manager: %v (KUBE_API_VERSIONS=%q)", err, kubeAPIVersions)
}
return m
}
// RegisterVersions adds the given group versions to the list of registered group versions.
func (m *APIRegistrationManager) RegisterVersions(availableVersions []schema.GroupVersion) {
for _, v := range availableVersions {
m.registeredVersions[v] = struct{}{}
}
}
// RegisterGroup adds the given group to the list of registered groups.
func (m *APIRegistrationManager) RegisterGroup(groupMeta apimachinery.GroupMeta) error {
groupName := groupMeta.GroupVersion.Group
if _, found := m.groupMetaMap[groupName]; found {
return fmt.Errorf("group %q is already registered in groupsMap: %v", groupName, m.groupMetaMap)
}
m.groupMetaMap[groupName] = &groupMeta
return nil
}
// EnableVersions adds the versions for the given group to the list of enabled versions.
// Note that the caller should call RegisterGroup before calling this method.
// The caller of this function is responsible to add the versions to scheme and RESTMapper.
func (m *APIRegistrationManager) EnableVersions(versions ...schema.GroupVersion) error {
var unregisteredVersions []schema.GroupVersion
for _, v := range versions {
if _, found := m.registeredVersions[v]; !found {
unregisteredVersions = append(unregisteredVersions, v)
}
m.enabledVersions[v] = struct{}{}
}
if len(unregisteredVersions) != 0 {
return fmt.Errorf("Please register versions before enabling them: %v", unregisteredVersions)
}
return nil
}
// IsAllowedVersion returns if the version is allowed by the KUBE_API_VERSIONS
// environment variable. If the environment variable is empty, then it always
// returns true.
func (m *APIRegistrationManager) IsAllowedVersion(v schema.GroupVersion) bool {
if len(m.envRequestedVersions) == 0 {
return true
}
for _, envGV := range m.envRequestedVersions {
if v == envGV {
return true
}
}
return false
}
// IsEnabledVersion returns if a version is enabled.
func (m *APIRegistrationManager) IsEnabledVersion(v schema.GroupVersion) bool {
_, found := m.enabledVersions[v]
return found
}
// EnabledVersions returns all enabled versions. Groups are randomly ordered, but versions within groups
// are priority order from best to worst
func (m *APIRegistrationManager) EnabledVersions() []schema.GroupVersion {
ret := []schema.GroupVersion{}
for _, groupMeta := range m.groupMetaMap {
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
}
return ret
}
// EnabledVersionsForGroup returns all enabled versions for a group in order of best to worst
func (m *APIRegistrationManager) EnabledVersionsForGroup(group string) []schema.GroupVersion {
groupMeta, ok := m.groupMetaMap[group]
if !ok {
return []schema.GroupVersion{}
}
ret := []schema.GroupVersion{}
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
return ret
}
// Group returns the metadata of a group if the group is registered, otherwise
// an error is returned.
func (m *APIRegistrationManager) Group(group string) (*apimachinery.GroupMeta, error) {
groupMeta, found := m.groupMetaMap[group]
if !found {
return nil, fmt.Errorf("group %v has not been registered", group)
}
groupMetaCopy := *groupMeta
return &groupMetaCopy, nil
}
// IsRegistered takes a string and determines if it's one of the registered groups
func (m *APIRegistrationManager) IsRegistered(group string) bool {
_, found := m.groupMetaMap[group]
return found
}
// IsRegisteredVersion returns if a version is registered.
func (m *APIRegistrationManager) IsRegisteredVersion(v schema.GroupVersion) bool {
_, found := m.registeredVersions[v]
return found
}
// RegisteredGroupVersions returns all registered group versions.
func (m *APIRegistrationManager) RegisteredGroupVersions() []schema.GroupVersion {
ret := []schema.GroupVersion{}
for groupVersion := range m.registeredVersions {
ret = append(ret, groupVersion)
}
return ret
}
// InterfacesFor is a union meta.VersionInterfacesFunc func for all registered types
func (m *APIRegistrationManager) InterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
groupMeta, err := m.Group(version.Group)
if err != nil {
return nil, err
}
return groupMeta.InterfacesFor(version)
}
// TODO: This is an expedient function, because we don't check if a Group is
// supported throughout the code base. We will abandon this function and
// checking the error returned by the Group() function.
func (m *APIRegistrationManager) GroupOrDie(group string) *apimachinery.GroupMeta {
groupMeta, found := m.groupMetaMap[group]
if !found {
if group == "" {
panic("The legacy v1 API is not registered.")
} else {
panic(fmt.Sprintf("Group %s is not registered.", group))
}
}
groupMetaCopy := *groupMeta
return &groupMetaCopy
}
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. if KUBE_API_VERSIONS is specified, then KUBE_API_VERSIONS in order, OR
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func (m *APIRegistrationManager) RESTMapper(versionPatterns ...schema.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for enabledVersion := range m.enabledVersions {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
groupMeta := m.groupMetaMap[enabledVersion.Group]
unionMapper = append(unionMapper, groupMeta.RESTMapper)
}
}
if len(versionPatterns) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
if len(m.envRequestedVersions) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range m.envRequestedVersions {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := m.prioritiesForGroups(prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for enabledVersion := range m.enabledVersions {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := m.prioritiesForGroups(remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func (m *APIRegistrationManager) prioritiesForGroups(groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, group := range groups {
availableVersions := m.EnabledVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
// AllPreferredGroupVersions returns the preferred versions of all registered
// groups in the form of "group1/version1,group2/version2,..."
func (m *APIRegistrationManager) AllPreferredGroupVersions() string {
if len(m.groupMetaMap) == 0 {
return ""
}
var defaults []string
for _, groupMeta := range m.groupMetaMap {
defaults = append(defaults, groupMeta.GroupVersion.String())
}
sort.Strings(defaults)
return strings.Join(defaults, ",")
}
// ValidateEnvRequestedVersions returns a list of versions that are requested in
// the KUBE_API_VERSIONS environment variable, but not enabled.
func (m *APIRegistrationManager) ValidateEnvRequestedVersions() []schema.GroupVersion {
var missingVersions []schema.GroupVersion
for _, v := range m.envRequestedVersions {
if _, found := m.enabledVersions[v]; !found {
missingVersions = append(missingVersions, v)
}
}
return missingVersions
}

View File

@ -1,71 +0,0 @@
/*
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.
*/
package registered
import (
"testing"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestAllPreferredGroupVersions(t *testing.T) {
testCases := []struct {
groupMetas []apimachinery.GroupMeta
expect string
}{
{
groupMetas: []apimachinery.GroupMeta{
{
GroupVersion: schema.GroupVersion{Group: "group1", Version: "v1"},
},
{
GroupVersion: schema.GroupVersion{Group: "group2", Version: "v2"},
},
{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
},
},
expect: "group1/v1,group2/v2,v1",
},
{
groupMetas: []apimachinery.GroupMeta{
{
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
},
},
expect: "v1",
},
{
groupMetas: []apimachinery.GroupMeta{},
expect: "",
},
}
for _, testCase := range testCases {
m, err := NewAPIRegistrationManager("")
if err != nil {
t.Fatalf("Unexpected failure to make a manager: %v", err)
}
for _, groupMeta := range testCase.groupMetas {
m.RegisterGroup(groupMeta)
}
output := m.AllPreferredGroupVersions()
if testCase.expect != output {
t.Errorf("Error. expect: %s, got: %s", testCase.expect, output)
}
}
}

View File

@ -1,87 +0,0 @@
/*
Copyright 2016 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 apimachinery
import (
"fmt"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupMeta stores the metadata of a group.
type GroupMeta struct {
// GroupVersion represents the preferred version of the group.
GroupVersion schema.GroupVersion
// GroupVersions is Group + all versions in that group.
GroupVersions []schema.GroupVersion
// SelfLinker can set or get the SelfLink field of all API types.
// TODO: when versioning changes, make this part of each API definition.
// TODO(lavalamp): Combine SelfLinker & ResourceVersioner interfaces, force all uses
// to go through the InterfacesFor method below.
SelfLinker runtime.SelfLinker
// RESTMapper provides the default mapping between REST paths and the objects declared in a Scheme and all known
// versions.
RESTMapper meta.RESTMapper
// InterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
// TODO: make this stop being a func pointer and always use the default
// function provided below once every place that populates this field has been changed.
InterfacesFor func(version schema.GroupVersion) (*meta.VersionInterfaces, error)
// InterfacesByVersion stores the per-version interfaces.
InterfacesByVersion map[schema.GroupVersion]*meta.VersionInterfaces
}
// DefaultInterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
// TODO: Remove the "Default" prefix.
func (gm *GroupMeta) DefaultInterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
if v, ok := gm.InterfacesByVersion[version]; ok {
return v, nil
}
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, gm.GroupVersions)
}
// AddVersionInterfaces adds the given version to the group. Only call during
// init, after that GroupMeta objects should be immutable. Not thread safe.
// (If you use this, be sure to set .InterfacesFor = .DefaultInterfacesFor)
// TODO: remove the "Interfaces" suffix and make this also maintain the
// .GroupVersions member.
func (gm *GroupMeta) AddVersionInterfaces(version schema.GroupVersion, interfaces *meta.VersionInterfaces) error {
if e, a := gm.GroupVersion.Group, version.Group; a != e {
return fmt.Errorf("got a version in group %v, but am in group %v", a, e)
}
if gm.InterfacesByVersion == nil {
gm.InterfacesByVersion = make(map[schema.GroupVersion]*meta.VersionInterfaces)
}
gm.InterfacesByVersion[version] = interfaces
// TODO: refactor to make the below error not possible, this function
// should *set* GroupVersions rather than depend on it.
for _, v := range gm.GroupVersions {
if v == version {
return nil
}
}
return fmt.Errorf("added a version interface without the corresponding version %v being in the list %#v", version, gm.GroupVersions)
}

View File

@ -1,43 +0,0 @@
/*
Copyright 2016 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 apimachinery
import (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestAdd(t *testing.T) {
gm := GroupMeta{
GroupVersion: schema.GroupVersion{
Group: "test",
Version: "v1",
},
GroupVersions: []schema.GroupVersion{{Group: "test", Version: "v1"}},
}
gm.AddVersionInterfaces(schema.GroupVersion{Group: "test", Version: "v1"}, nil)
if e, a := 1, len(gm.InterfacesByVersion); e != a {
t.Errorf("expected %v, got %v", e, a)
}
// GroupVersions is unchanged
if e, a := 1, len(gm.GroupVersions); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}

9
vendor/k8s.io/apimachinery/pkg/apis/OWNERS generated vendored Normal file
View File

@ -0,0 +1,9 @@
# Disable inheritance as this is an api owners file
options:
no_parent_owners: true
approvers:
- api-approvers
reviewers:
- api-reviewers
labels:
- kind/api-change

7
vendor/k8s.io/apimachinery/pkg/apis/config/OWNERS generated vendored Normal file
View File

@ -0,0 +1,7 @@
approvers:
- api-approvers
- sttts
- luxas
reviewers:
- api-reviewers
- hanxiaoshuai

19
vendor/k8s.io/apimachinery/pkg/apis/config/doc.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
/*
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.
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.
*/
// +k8s:deepcopy-gen=package
package config // import "k8s.io/apimachinery/pkg/apis/config"

33
vendor/k8s.io/apimachinery/pkg/apis/config/types.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
/*
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.
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 config
// ClientConnectionConfiguration contains details for constructing a client.
type ClientConnectionConfiguration struct {
// kubeconfig is the path to a KubeConfig file.
Kubeconfig string
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
// default value of 'application/json'. This field will control all connections to the server used by a particular
// client.
AcceptContentTypes string
// contentType is the content type used when sending data to the server from this client.
ContentType string
// qps controls the number of queries per second allowed for this connection.
QPS float32
// burst allows extra queries to accumulate when a client is exceeding its rate.
Burst int32
}

View File

@ -0,0 +1,37 @@
/*
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.
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 v1alpha1
import (
"k8s.io/apimachinery/pkg/apis/config"
"k8s.io/apimachinery/pkg/conversion"
)
// Important! The public back-and-forth conversion functions for the types in this generic
// package with ComponentConfig types need to be manually exposed like this in order for
// other packages that reference this package to be able to call these conversion functions
// in an autogenerated manner.
// TODO: Fix the bug in conversion-gen so it automatically discovers these Convert_* functions
// in autogenerated code as well.
func Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error {
return autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in, out, s)
}
func Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error {
return autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in, out, s)
}

View File

@ -0,0 +1,38 @@
/*
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.
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 v1alpha1
// RecommendedDefaultClientConnectionConfiguration defaults a pointer to a
// ClientConnectionConfiguration struct. This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultClientConnectionConfiguration(obj *ClientConnectionConfiguration) {
if len(obj.ContentType) == 0 {
obj.ContentType = "application/vnd.kubernetes.protobuf"
}
if obj.QPS == 0.0 {
obj.QPS = 50.0
}
if obj.Burst == 0 {
obj.Burst = 100
}
}

View File

@ -0,0 +1,20 @@
/*
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.
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.
*/
// +k8s:deepcopy-gen=package
// +k8s:conversion-gen=k8s.io/apimachinery/pkg/apis/config
package v1alpha1 // import "k8s.io/apimachinery/pkg/apis/config/v1alpha1"

View File

@ -0,0 +1,31 @@
/*
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.
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 v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
)
var (
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
SchemeBuilder runtime.SchemeBuilder
// localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package,
// defaulting and conversion init funcs are registered as well.
localSchemeBuilder = &SchemeBuilder
// AddToScheme is a global function that registers this API group & version to a scheme
AddToScheme = localSchemeBuilder.AddToScheme
)

View File

@ -0,0 +1,33 @@
/*
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.
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 v1alpha1
// ClientConnectionConfiguration contains details for constructing a client.
type ClientConnectionConfiguration struct {
// kubeconfig is the path to a KubeConfig file.
Kubeconfig string `json:"kubeconfig"`
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
// default value of 'application/json'. This field will control all connections to the server used by a particular
// client.
AcceptContentTypes string `json:"acceptContentTypes"`
// contentType is the content type used when sending data to the server from this client.
ContentType string `json:"contentType"`
// qps controls the number of queries per second allowed for this connection.
QPS float32 `json:"qps"`
// burst allows extra queries to accumulate when a client is exceeding its rate.
Burst int32 `json:"burst"`
}

View File

@ -0,0 +1,75 @@
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha1
import (
config "k8s.io/apimachinery/pkg/apis/config"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*ClientConnectionConfiguration)(nil), (*config.ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(a.(*ClientConnectionConfiguration), b.(*config.ClientConnectionConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ClientConnectionConfiguration)(nil), (*config.ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(a.(*ClientConnectionConfiguration), b.(*config.ClientConnectionConfiguration), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error {
out.Kubeconfig = in.Kubeconfig
out.AcceptContentTypes = in.AcceptContentTypes
out.ContentType = in.ContentType
out.QPS = in.QPS
out.Burst = in.Burst
return nil
}
func autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error {
out.Kubeconfig = in.Kubeconfig
out.AcceptContentTypes = in.AcceptContentTypes
out.ContentType = in.ContentType
out.QPS = in.QPS
out.Burst = in.Burst
return nil
}

View File

@ -0,0 +1,37 @@
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration.
func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration {
if in == nil {
return nil
}
out := new(ClientConnectionConfiguration)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,31 @@
/*
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.
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 validation
import (
"k8s.io/apimachinery/pkg/apis/config"
"k8s.io/apimachinery/pkg/util/validation/field"
)
// ValidateClientConnectionConfiguration ensures validation of the ClientConnectionConfiguration struct
func ValidateClientConnectionConfiguration(cc *config.ClientConnectionConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if cc.Burst < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("burst"), cc.Burst, "must be non-negative"))
}
return allErrs
}

View File

@ -0,0 +1,66 @@
/*
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.
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 validation
import (
"k8s.io/apimachinery/pkg/apis/config"
"k8s.io/apimachinery/pkg/util/validation/field"
"testing"
)
func TestValidateClientConnectionConfiguration(t *testing.T) {
validConfig := &config.ClientConnectionConfiguration{
AcceptContentTypes: "application/json",
ContentType: "application/json",
QPS: 10,
Burst: 10,
}
qpsLessThanZero := validConfig.DeepCopy()
qpsLessThanZero.QPS = -1
burstLessThanZero := validConfig.DeepCopy()
burstLessThanZero.Burst = -1
scenarios := map[string]struct {
expectedToFail bool
config *config.ClientConnectionConfiguration
}{
"good": {
expectedToFail: false,
config: validConfig,
},
"good-qps-less-than-zero": {
expectedToFail: false,
config: qpsLessThanZero,
},
"bad-burst-less-then-zero": {
expectedToFail: true,
config: burstLessThanZero,
},
}
for name, scenario := range scenarios {
errs := ValidateClientConnectionConfiguration(scenario.config, field.NewPath("clientConnectionConfiguration"))
if len(errs) == 0 && scenario.expectedToFail {
t.Errorf("Unexpected success for scenario: %s", name)
}
if len(errs) > 0 && !scenario.expectedToFail {
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
}
}
}

View File

@ -0,0 +1,37 @@
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package config
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration.
func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration {
if in == nil {
return nil
}
out := new(ClientConnectionConfiguration)
in.DeepCopyInto(out)
return out
}

View File

@ -1,36 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["fuzzer.go"],
importpath = "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
deps = [
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -25,9 +25,9 @@ import (
"github.com/google/gofuzz"
apitesting "k8s.io/apimachinery/pkg/api/apitesting"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
"k8s.io/apimachinery/pkg/api/resource"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
@ -181,16 +181,45 @@ func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
j.Kind = ""
},
func(j *metav1.ObjectMeta, c fuzz.Continue) {
j.Name = c.RandString()
c.FuzzNoCustom(j)
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.SelfLink = c.RandString()
j.UID = types.UID(c.RandString())
j.GenerateName = c.RandString()
var sec, nsec int64
c.Fuzz(&sec)
c.Fuzz(&nsec)
j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy()
if j.DeletionTimestamp != nil {
c.Fuzz(&sec)
c.Fuzz(&nsec)
t := metav1.Unix(sec, nsec).Rfc3339Copy()
j.DeletionTimestamp = &t
}
if len(j.Labels) == 0 {
j.Labels = nil
} else {
delete(j.Labels, "")
}
if len(j.Annotations) == 0 {
j.Annotations = nil
} else {
delete(j.Annotations, "")
}
if len(j.OwnerReferences) == 0 {
j.OwnerReferences = nil
}
if len(j.Finalizers) == 0 {
j.Finalizers = nil
}
},
func(j *metav1.Initializers, c fuzz.Continue) {
c.FuzzNoCustom(j)
if len(j.Pending) == 0 {
j.Pending = nil
}
},
func(j *metav1.ListMeta, c fuzz.Continue) {
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
@ -268,7 +297,7 @@ func v1alpha1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
case 0:
r.Cells[i] = c.RandString()
case 1:
r.Cells[i] = c.Uint64()
r.Cells[i] = c.Int63()
case 2:
r.Cells[i] = c.RandBool()
case 3:
@ -280,7 +309,7 @@ func v1alpha1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
case 4:
x := make([]interface{}, c.Intn(10))
for i := range x {
x[i] = c.Uint64()
x[i] = c.Int63()
}
r.Cells[i] = x
default:

View File

@ -1,59 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"register_test.go",
"roundtrip_test.go",
],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"conversion.go",
"doc.go",
"register.go",
"types.go",
"zz_generated.conversion.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/apimachinery/pkg/apis/meta/internalversion",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels: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/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -17,11 +17,8 @@ limitations under the License.
package internalversion
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/util/validation/field"
)
func Convert_internalversion_ListOptions_To_v1_ListOptions(in *ListOptions, out *metav1.ListOptions, s conversion.Scope) error {
@ -55,23 +52,3 @@ func Convert_v1_ListOptions_To_internalversion_ListOptions(in *metav1.ListOption
out.Continue = in.Continue
return nil
}
func Convert_map_to_v1_LabelSelector(in *map[string]string, out *metav1.LabelSelector, s conversion.Scope) error {
if in == nil {
return nil
}
out = new(metav1.LabelSelector)
for labelKey, labelValue := range *in {
metav1.AddLabelToSelector(out, labelKey, labelValue)
}
return nil
}
func Convert_v1_LabelSelector_to_map(in *metav1.LabelSelector, out *map[string]string, s conversion.Scope) error {
var err error
*out, err = metav1.LabelSelectorAsMap(in)
if err != nil {
err = field.Invalid(field.NewPath("labelSelector"), *in, fmt.Sprintf("cannot convert to old selector: %v", err))
}
return err
}

View File

@ -57,19 +57,22 @@ func addToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion)
if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil {
return err
}
scheme.AddConversionFuncs(
err := scheme.AddConversionFuncs(
metav1.Convert_string_To_labels_Selector,
metav1.Convert_labels_Selector_To_string,
metav1.Convert_string_To_fields_Selector,
metav1.Convert_fields_Selector_To_string,
Convert_map_to_v1_LabelSelector,
Convert_v1_LabelSelector_to_map,
metav1.Convert_Map_string_To_string_To_v1_LabelSelector,
metav1.Convert_v1_LabelSelector_To_Map_string_To_string,
Convert_internalversion_ListOptions_To_v1_ListOptions,
Convert_v1_ListOptions_To_internalversion_ListOptions,
)
if err != nil {
return err
}
// ListOptions is the only options struct which needs conversion (it exposes labels and fields
// as selectors for convenience). The other types have only a single representation today.
scheme.AddKnownTypes(SchemeGroupVersion,
@ -77,6 +80,8 @@ func addToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion)
&metav1.GetOptions{},
&metav1.ExportOptions{},
&metav1.DeleteOptions{},
&metav1.CreateOptions{},
&metav1.UpdateOptions{},
)
scheme.AddKnownTypes(SchemeGroupVersion,
&metav1beta1.Table{},
@ -91,7 +96,10 @@ func addToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion)
&metav1beta1.PartialObjectMetadataList{},
)
// Allow delete options to be decoded across all version in this scheme (we may want to be more clever than this)
scheme.AddUnversionedTypes(SchemeGroupVersion, &metav1.DeleteOptions{})
scheme.AddUnversionedTypes(SchemeGroupVersion,
&metav1.DeleteOptions{},
&metav1.CreateOptions{},
&metav1.UpdateOptions{})
metav1.AddToGroupVersion(scheme, metav1.SchemeGroupVersion)
return nil
}

View File

@ -19,7 +19,7 @@ package internalversion
import (
"testing"
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
"k8s.io/apimachinery/pkg/apis/meta/fuzzer"
)

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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.
@ -34,13 +34,38 @@ func init() {
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_internalversion_List_To_v1_List,
Convert_v1_List_To_internalversion_List,
Convert_internalversion_ListOptions_To_v1_ListOptions,
Convert_v1_ListOptions_To_internalversion_ListOptions,
)
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*List)(nil), (*v1.List)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_internalversion_List_To_v1_List(a.(*List), b.(*v1.List), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.List)(nil), (*List)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_List_To_internalversion_List(a.(*v1.List), b.(*List), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*ListOptions)(nil), (*v1.ListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_internalversion_ListOptions_To_v1_ListOptions(a.(*ListOptions), b.(*v1.ListOptions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.ListOptions)(nil), (*ListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_ListOptions_To_internalversion_ListOptions(a.(*v1.ListOptions), b.(*ListOptions), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*ListOptions)(nil), (*v1.ListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_internalversion_ListOptions_To_v1_ListOptions(a.(*ListOptions), b.(*v1.ListOptions), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*v1.ListOptions)(nil), (*ListOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_ListOptions_To_internalversion_ListOptions(a.(*v1.ListOptions), b.(*ListOptions), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_internalversion_List_To_v1_List(in *List, out *v1.List, s conversion.Scope) error {

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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.
@ -33,9 +33,7 @@ func (in *List) DeepCopyInto(out *List) {
in, out := &in.Items, &out.Items
*out = make([]runtime.Object, len(*in))
for i := range *in {
if (*in)[i] == nil {
(*out)[i] = nil
} else {
if (*in)[i] != nil {
(*out)[i] = (*in)[i].DeepCopyObject()
}
}
@ -65,24 +63,16 @@ func (in *List) DeepCopyObject() runtime.Object {
func (in *ListOptions) DeepCopyInto(out *ListOptions) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.LabelSelector == nil {
out.LabelSelector = nil
} else {
if in.LabelSelector != nil {
out.LabelSelector = in.LabelSelector.DeepCopySelector()
}
if in.FieldSelector == nil {
out.FieldSelector = nil
} else {
if in.FieldSelector != nil {
out.FieldSelector = in.FieldSelector.DeepCopySelector()
}
if in.TimeoutSeconds != nil {
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
*out = new(int64)
**out = **in
}
return
}

View File

@ -1,101 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"controller_ref_test.go",
"duration_test.go",
"group_version_test.go",
"helpers_test.go",
"labels_test.go",
"micro_time_test.go",
"time_test.go",
"types_test.go",
],
embed = [":go_default_library"],
deps = [
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"controller_ref.go",
"conversion.go",
"doc.go",
"duration.go",
"generated.pb.go",
"group_version.go",
"helpers.go",
"labels.go",
"meta.go",
"micro_time.go",
"micro_time_proto.go",
"register.go",
"time.go",
"time_proto.go",
"types.go",
"types_swagger_doc_generated.go",
"watch.go",
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
],
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1",
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels: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/selection:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:all-srcs",
],
tags = ["automanaged"],
)
filegroup(
name = "go_default_library_protos",
srcs = ["generated.proto"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_xtest",
srcs = ["conversion_test.go"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)

View File

@ -33,17 +33,17 @@ func AddConversionFuncs(scheme *runtime.Scheme) error {
return scheme.AddConversionFuncs(
Convert_v1_TypeMeta_To_v1_TypeMeta,
Convert_unversioned_ListMeta_To_unversioned_ListMeta,
Convert_v1_ListMeta_To_v1_ListMeta,
Convert_intstr_IntOrString_To_intstr_IntOrString,
Convert_unversioned_Time_To_unversioned_Time,
Convert_unversioned_MicroTime_To_unversioned_MicroTime,
Convert_Pointer_v1_Duration_To_v1_Duration,
Convert_v1_Duration_To_Pointer_v1_Duration,
Convert_Slice_string_To_unversioned_Time,
Convert_Slice_string_To_v1_Time,
Convert_v1_Time_To_v1_Time,
Convert_v1_MicroTime_To_v1_MicroTime,
Convert_resource_Quantity_To_resource_Quantity,
@ -71,10 +71,12 @@ func AddConversionFuncs(scheme *runtime.Scheme) error {
Convert_Pointer_float64_To_float64,
Convert_float64_To_Pointer_float64,
Convert_map_to_unversioned_LabelSelector,
Convert_unversioned_LabelSelector_to_map,
Convert_Map_string_To_string_To_v1_LabelSelector,
Convert_v1_LabelSelector_To_Map_string_To_string,
Convert_Slice_string_To_Slice_int32,
Convert_Slice_string_To_v1_DeletionPropagation,
)
}
@ -185,7 +187,7 @@ func Convert_v1_TypeMeta_To_v1_TypeMeta(in, out *TypeMeta, s conversion.Scope) e
}
// +k8s:conversion-fn=copy-only
func Convert_unversioned_ListMeta_To_unversioned_ListMeta(in, out *ListMeta, s conversion.Scope) error {
func Convert_v1_ListMeta_To_v1_ListMeta(in, out *ListMeta, s conversion.Scope) error {
*out = *in
return nil
}
@ -197,7 +199,14 @@ func Convert_intstr_IntOrString_To_intstr_IntOrString(in, out *intstr.IntOrStrin
}
// +k8s:conversion-fn=copy-only
func Convert_unversioned_Time_To_unversioned_Time(in *Time, out *Time, s conversion.Scope) error {
func Convert_v1_Time_To_v1_Time(in *Time, out *Time, s conversion.Scope) error {
// Cannot deep copy these, because time.Time has unexported fields.
*out = *in
return nil
}
// +k8s:conversion-fn=copy-only
func Convert_v1_MicroTime_To_v1_MicroTime(in *MicroTime, out *MicroTime, s conversion.Scope) error {
// Cannot deep copy these, because time.Time has unexported fields.
*out = *in
return nil
@ -218,14 +227,8 @@ func Convert_v1_Duration_To_Pointer_v1_Duration(in *Duration, out **Duration, s
return nil
}
func Convert_unversioned_MicroTime_To_unversioned_MicroTime(in *MicroTime, out *MicroTime, s conversion.Scope) error {
// Cannot deep copy these, because time.Time has unexported fields.
*out = *in
return nil
}
// Convert_Slice_string_To_unversioned_Time allows converting a URL query parameter value
func Convert_Slice_string_To_unversioned_Time(input *[]string, out *Time, s conversion.Scope) error {
// Convert_Slice_string_To_v1_Time allows converting a URL query parameter value
func Convert_Slice_string_To_v1_Time(input *[]string, out *Time, s conversion.Scope) error {
str := ""
if len(*input) > 0 {
str = (*input)[0]
@ -273,7 +276,7 @@ func Convert_resource_Quantity_To_resource_Quantity(in *resource.Quantity, out *
return nil
}
func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelSelector, s conversion.Scope) error {
func Convert_Map_string_To_string_To_v1_LabelSelector(in *map[string]string, out *LabelSelector, s conversion.Scope) error {
if in == nil {
return nil
}
@ -283,7 +286,7 @@ func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelS
return nil
}
func Convert_unversioned_LabelSelector_to_map(in *LabelSelector, out *map[string]string, s conversion.Scope) error {
func Convert_v1_LabelSelector_To_Map_string_To_string(in *LabelSelector, out *map[string]string, s conversion.Scope) error {
var err error
*out, err = LabelSelectorAsMap(in)
return err
@ -304,3 +307,13 @@ func Convert_Slice_string_To_Slice_int32(in *[]string, out *[]int32, s conversio
}
return nil
}
// Convert_Slice_string_To_v1_DeletionPropagation allows converting a URL query parameter propagationPolicy
func Convert_Slice_string_To_v1_DeletionPropagation(input *[]string, out *DeletionPropagation, s conversion.Scope) error {
if len(*input) > 0 {
*out = DeletionPropagation((*input)[0])
} else {
*out = ""
}
return nil
}

View File

@ -33,13 +33,13 @@ func TestMapToLabelSelectorRoundTrip(t *testing.T) {
}
for _, in := range inputs {
ls := &v1.LabelSelector{}
if err := v1.Convert_map_to_unversioned_LabelSelector(&in, ls, nil); err != nil {
t.Errorf("Convert_map_to_unversioned_LabelSelector(%#v): %v", in, err)
if err := v1.Convert_Map_string_To_string_To_v1_LabelSelector(&in, ls, nil); err != nil {
t.Errorf("Convert_Map_string_To_string_To_v1_LabelSelector(%#v): %v", in, err)
continue
}
out := map[string]string{}
if err := v1.Convert_unversioned_LabelSelector_to_map(ls, &out, nil); err != nil {
t.Errorf("Convert_unversioned_LabelSelector_to_map(%#v): %v", ls, err)
if err := v1.Convert_v1_LabelSelector_To_Map_string_To_string(ls, &out, nil); err != nil {
t.Errorf("Convert_v1_LabelSelector_To_Map_string_To_string(%#v): %v", ls, err)
continue
}
if !apiequality.Semantic.DeepEqual(in, out) {
@ -47,3 +47,38 @@ func TestMapToLabelSelectorRoundTrip(t *testing.T) {
}
}
}
func TestConvertSliceStringToDeletionPropagation(t *testing.T) {
tcs := []struct {
Input []string
Output v1.DeletionPropagation
}{
{
Input: nil,
Output: "",
},
{
Input: []string{},
Output: "",
},
{
Input: []string{"foo"},
Output: "foo",
},
{
Input: []string{"bar", "foo"},
Output: "bar",
},
}
for _, tc := range tcs {
var dp v1.DeletionPropagation
if err := v1.Convert_Slice_string_To_v1_DeletionPropagation(&tc.Input, &dp, nil); err != nil {
t.Errorf("Convert_Slice_string_To_v1_DeletionPropagation(%#v): %v", tc.Input, err)
continue
}
if !apiequality.Semantic.DeepEqual(dp, tc.Output) {
t.Errorf("slice string to DeletionPropagation conversion failed: got %v; want %v", dp, tc.Output)
}
}
}

View File

@ -19,4 +19,5 @@ limitations under the License.
// +k8s:defaulter-gen=TypeMeta
// +groupName=meta.k8s.io
package v1 // import "k8s.io/apimachinery/pkg/apis/meta/v1"

View File

@ -31,7 +31,10 @@ type Duration struct {
// UnmarshalJSON implements the json.Unmarshaller interface.
func (d *Duration) UnmarshalJSON(b []byte) error {
var str string
json.Unmarshal(b, &str)
err := json.Unmarshal(b, &str)
if err != nil {
return err
}
pd, err := time.ParseDuration(str)
if err != nil {

View File

@ -21,7 +21,7 @@ import (
"testing"
"time"
"github.com/ghodss/yaml"
"sigs.k8s.io/yaml"
)
type DurationHolder struct {

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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.
@ -23,7 +23,6 @@ package k8s.io.apimachinery.pkg.apis.meta.v1;
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1";
@ -49,6 +48,7 @@ message APIGroup {
// The server returns only those CIDRs that it thinks that the client can match.
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP.
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.
// +optional
repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 4;
}
@ -107,7 +107,7 @@ message APIResourceList {
// APIVersions lists the versions that are available, to allow clients to
// discover the API at /api, which is the root path of the legacy v1 API.
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
message APIVersions {
@ -124,6 +124,21 @@ message APIVersions {
repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 2;
}
// CreateOptions may be provided when creating an API object.
message CreateOptions {
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
repeated string dryRun = 1;
// If IncludeUninitialized is specified, the object may be
// returned without completing initialization.
optional bool includeUninitialized = 2;
}
// DeleteOptions may be provided when deleting an API object.
message DeleteOptions {
// The duration in seconds before the object should be deleted. Value must be non-negative integer.
@ -155,6 +170,14 @@ message DeleteOptions {
// foreground.
// +optional
optional string propagationPolicy = 4;
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
repeated string dryRun = 5;
}
// Duration is a wrapper around time.Duration which supports correct
@ -188,7 +211,7 @@ message GetOptions {
// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
// concepts during lookup stages without having partially valid types
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
message GroupKind {
optional string group = 1;
@ -198,7 +221,7 @@ message GroupKind {
// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
// concepts during lookup stages without having partially valid types
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
message GroupResource {
optional string group = 1;
@ -207,7 +230,7 @@ message GroupResource {
}
// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
message GroupVersion {
optional string group = 1;
@ -228,7 +251,7 @@ message GroupVersionForDiscovery {
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
message GroupVersionKind {
optional string group = 1;
@ -240,7 +263,7 @@ message GroupVersionKind {
// GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
//
//
// +protobuf.options.(gogoproto.goproto_stringer)=false
message GroupVersionResource {
optional string group = 1;
@ -338,9 +361,10 @@ message ListMeta {
// continue may be set if the user set a limit on the number of items returned, and indicates that
// the server has more data available. The value is opaque and may be used to issue another request
// to the endpoint that served this list to retrieve the next set of available objects. Continuing a
// list may not be possible if the server configuration has changed or more than a few minutes have
// passed. The resourceVersion field returned when using this continue value will be identical to
// the value in the first response.
// consistent list may not be possible if the server configuration has changed or more than a few
// minutes have passed. The resourceVersion field returned when using this continue value will be
// identical to the value in the first response, unless you have received this token from an error
// message.
optional string continue = 3;
}
@ -387,7 +411,7 @@ message ListOptions {
// more results are available. Servers may choose not to support the limit argument and will return
// all of the available results. If limit is specified and the continue field is empty, clients may
// assume that no more results are available. This field is not supported if watch is true.
//
//
// The server guarantees that the objects returned when using continue will be identical to issuing
// a single list call without a limit - that is, no objects created, modified, or deleted after the
// first request is issued will be included in any subsequent continued requests. This is sometimes
@ -397,19 +421,25 @@ message ListOptions {
// result was calculated is returned.
optional int64 limit = 7;
// The continue option should be set when retrieving more results from the server. Since this value
// is server defined, clients may only use the continue value from a previous query result with
// identical query parameters (except for the value of continue) and the server may reject a continue
// value it does not recognize. If the specified continue value is no longer valid whether due to
// expiration (generally five to fifteen minutes) or a configuration change on the server the server
// will respond with a 410 ResourceExpired error indicating the client must restart their list without
// the continue field. This field is not supported when watch is true. Clients may start a watch from
// the last resourceVersion value returned by the server and not miss any modifications.
// The continue option should be set when retrieving more results from the server. Since this value is
// server defined, clients may only use the continue value from a previous query result with identical
// query parameters (except for the value of continue) and the server may reject a continue value it
// does not recognize. If the specified continue value is no longer valid whether due to expiration
// (generally five to fifteen minutes) or a configuration change on the server, the server will
// respond with a 410 ResourceExpired error together with a continue token. If the client needs a
// consistent list, it must restart their list without the continue field. Otherwise, the client may
// send another list request with the token received with the 410 error, the server will respond with
// a list starting from the next key, but from the latest snapshot, which is inconsistent from the
// previous list results - objects that are created, modified, or deleted after the first list request
// will be included in the response, as long as their keys are after the "next key".
//
// This field is not supported when watch is true. Clients may start a watch from the last
// resourceVersion value returned by the server and not miss any modifications.
optional string continue = 8;
}
// MicroTime is version of Time with microsecond level precision.
//
//
// +protobuf.options.marshal=false
// +protobuf.as=Timestamp
// +protobuf.options.(gogoproto.goproto_stringer)=false
@ -445,12 +475,12 @@ message ObjectMeta {
// The provided value has the same validation rules as the Name field,
// and may be truncated by the length of the suffix required to make the value
// unique on the server.
//
//
// If this field is specified and the generated name exists, the server will
// NOT return a 409 - instead, it will either return 201 Created or 500 with Reason
// ServerTimeout indicating a unique name could not be found in the time allotted, and the client
// should retry (optionally after the time indicated in the Retry-After header).
//
//
// Applied only if Name is not specified.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency
// +optional
@ -460,7 +490,7 @@ message ObjectMeta {
// equivalent to the "default" namespace, but "default" is the canonical representation.
// Not all objects are required to be scoped to a namespace - the value of this field for
// those objects will be empty.
//
//
// Must be a DNS_LABEL.
// Cannot be updated.
// More info: http://kubernetes.io/docs/user-guide/namespaces
@ -476,7 +506,7 @@ message ObjectMeta {
// UID is the unique in time and space value for this object. It is typically generated by
// the server on successful creation of a resource and is not allowed to change on PUT
// operations.
//
//
// Populated by the system.
// Read-only.
// More info: http://kubernetes.io/docs/user-guide/identifiers#uids
@ -488,7 +518,7 @@ message ObjectMeta {
// concurrency, change detection, and the watch operation on a resource or set of resources.
// Clients must treat these values as opaque and passed unmodified back to the server.
// They may only be valid for a particular resource or set of resources.
//
//
// Populated by the system.
// Read-only.
// Value must be treated as opaque by clients and .
@ -504,7 +534,7 @@ message ObjectMeta {
// CreationTimestamp is a timestamp representing the server time when this object was
// created. It is not guaranteed to be set in happens-before order across separate operations.
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
//
//
// Populated by the system.
// Read-only.
// Null for lists.
@ -526,7 +556,7 @@ message ObjectMeta {
// exist after this timestamp, until an administrator or automated process can determine the
// resource is fully terminated.
// If not set, graceful deletion of the object has not been requested.
//
//
// Populated by the system when a graceful deletion is requested.
// Read-only.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
@ -568,7 +598,7 @@ message ObjectMeta {
// this object has been completely initialized. Otherwise, the object is considered uninitialized
// and is hidden (in list/watch and get calls) from clients that haven't explicitly asked to
// observe uninitialized objects.
//
//
// When an object is created, the system will populate this list with the current set of initializers.
// Only privileged users may set or modify this list. Once it is empty, it may not be modified further
// by any user.
@ -590,8 +620,8 @@ message ObjectMeta {
}
// OwnerReference contains enough information to let you identify an owning
// object. Currently, an owning object must be in the same namespace, so there
// is no namespace field.
// object. An owning object must be in the same namespace as the dependent, or
// be cluster-scoped, so there is no namespace field.
message OwnerReference {
// API version of the referent.
optional string apiVersion = 5;
@ -704,7 +734,7 @@ message StatusCause {
// Arrays are zero-indexed. Fields may appear more than once in an array of
// causes due to fields having multiple errors.
// Optional.
//
//
// Examples:
// "name" - the field "name" on the current resource
// "items[0].name" - the field "name" on the first array entry in "items"
@ -755,7 +785,7 @@ message StatusDetails {
// Time is a wrapper around time.Time which supports correct
// marshaling to YAML and JSON. Wrappers are provided for many
// of the factory methods that the time package offers.
//
//
// +protobuf.options.marshal=false
// +protobuf.as=Timestamp
// +protobuf.options.(gogoproto.goproto_stringer)=false
@ -791,7 +821,7 @@ message Timestamp {
// TypeMeta describes an individual object in an API response or request
// with strings representing the type of the object and its API schema version.
// Structures that are versioned or persisted should inline TypeMeta.
//
//
// +k8s:deepcopy-gen=false
message TypeMeta {
// Kind is a string value representing the REST resource this object represents.
@ -810,8 +840,19 @@ message TypeMeta {
optional string apiVersion = 2;
}
// UpdateOptions may be provided when updating an API object.
message UpdateOptions {
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
repeated string dryRun = 1;
}
// Verbs masks the value so protobuf can generate
//
//
// +protobuf.nullable=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
message Verbs {
@ -821,7 +862,7 @@ message Verbs {
}
// Event represents a single event to a watched resource.
//
//
// +protobuf=true
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -17,11 +17,11 @@ limitations under the License.
package v1
import (
"encoding/json"
gojson "encoding/json"
"reflect"
"testing"
jsoniter "github.com/json-iterator/go"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
type GroupVersionHolder struct {
@ -40,14 +40,15 @@ func TestGroupVersionUnmarshalJSON(t *testing.T) {
for _, c := range cases {
var result GroupVersionHolder
// test golang lib's JSON codec
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
if err := gojson.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("JSON codec failed to unmarshal input '%v': %v", c.input, err)
}
if !reflect.DeepEqual(result.GV, c.expect) {
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
}
// test the json-iterator codec
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(c.input, &result); err != nil {
iter := json.CaseSensitiveJsonIterator()
if err := iter.Unmarshal(c.input, &result); err != nil {
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
}
if !reflect.DeepEqual(result.GV, c.expect) {
@ -67,7 +68,7 @@ func TestGroupVersionMarshalJSON(t *testing.T) {
for _, c := range cases {
input := GroupVersionHolder{c.input}
result, err := json.Marshal(&input)
result, err := gojson.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input '%v': %v", input, err)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package v1
import (
"fmt"
"reflect"
"strings"
"testing"
@ -70,15 +71,21 @@ func TestLabelSelectorAsSelector(t *testing.T) {
}
for i, tc := range tc {
inCopy := tc.in.DeepCopy()
out, err := LabelSelectorAsSelector(tc.in)
// after calling LabelSelectorAsSelector, tc.in shouldn't be modified
if !reflect.DeepEqual(inCopy, tc.in) {
t.Errorf("[%v]expected:\n\t%#v\nbut got:\n\t%#v", i, inCopy, tc.in)
}
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
if !reflect.DeepEqual(out, tc.out) {
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
// fmt.Sprint() over String() as nil.String() will panic
if fmt.Sprint(out) != fmt.Sprint(tc.out) {
t.Errorf("[%v]expected:\n\t%s\nbut got:\n\t%s", i, fmt.Sprint(tc.out), fmt.Sprint(out))
}
}
}

View File

@ -162,55 +162,9 @@ func (meta *ObjectMeta) GetInitializers() *Initializers { return m
func (meta *ObjectMeta) SetInitializers(initializers *Initializers) { meta.Initializers = initializers }
func (meta *ObjectMeta) GetFinalizers() []string { return meta.Finalizers }
func (meta *ObjectMeta) SetFinalizers(finalizers []string) { meta.Finalizers = finalizers }
func (meta *ObjectMeta) GetOwnerReferences() []OwnerReference {
if meta.OwnerReferences == nil {
return nil
}
ret := make([]OwnerReference, len(meta.OwnerReferences))
for i := 0; i < len(meta.OwnerReferences); i++ {
ret[i].Kind = meta.OwnerReferences[i].Kind
ret[i].Name = meta.OwnerReferences[i].Name
ret[i].UID = meta.OwnerReferences[i].UID
ret[i].APIVersion = meta.OwnerReferences[i].APIVersion
if meta.OwnerReferences[i].Controller != nil {
value := *meta.OwnerReferences[i].Controller
ret[i].Controller = &value
}
if meta.OwnerReferences[i].BlockOwnerDeletion != nil {
value := *meta.OwnerReferences[i].BlockOwnerDeletion
ret[i].BlockOwnerDeletion = &value
}
}
return ret
}
func (meta *ObjectMeta) GetOwnerReferences() []OwnerReference { return meta.OwnerReferences }
func (meta *ObjectMeta) SetOwnerReferences(references []OwnerReference) {
if references == nil {
meta.OwnerReferences = nil
return
}
newReferences := make([]OwnerReference, len(references))
for i := 0; i < len(references); i++ {
newReferences[i].Kind = references[i].Kind
newReferences[i].Name = references[i].Name
newReferences[i].UID = references[i].UID
newReferences[i].APIVersion = references[i].APIVersion
if references[i].Controller != nil {
value := *references[i].Controller
newReferences[i].Controller = &value
}
if references[i].BlockOwnerDeletion != nil {
value := *references[i].BlockOwnerDeletion
newReferences[i].BlockOwnerDeletion = &value
}
}
meta.OwnerReferences = newReferences
}
func (meta *ObjectMeta) GetClusterName() string {
return meta.ClusterName
}
func (meta *ObjectMeta) SetClusterName(clusterName string) {
meta.ClusterName = clusterName
meta.OwnerReferences = references
}
func (meta *ObjectMeta) GetClusterName() string { return meta.ClusterName }
func (meta *ObjectMeta) SetClusterName(clusterName string) { meta.ClusterName = clusterName }

View File

@ -104,7 +104,10 @@ func (t *MicroTime) UnmarshalJSON(b []byte) error {
}
var str string
json.Unmarshal(b, &str)
err := json.Unmarshal(b, &str)
if err != nil {
return err
}
pt, err := time.Parse(RFC3339Micro, str)
if err != nil {

View File

@ -22,7 +22,7 @@ import (
"testing"
"time"
"github.com/ghodss/yaml"
"sigs.k8s.io/yaml"
)
type MicroTimeHolder struct {
@ -35,8 +35,8 @@ func TestMicroTimeMarshalYAML(t *testing.T) {
result string
}{
{MicroTime{}, "t: null\n"},
{DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05.000000Z\n"},
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05.000000Z\n"},
{DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: \"1998-05-05T05:05:05.000000Z\"\n"},
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: \"1998-05-05T05:05:05.000000Z\"\n"},
}
for _, c := range cases {

View File

@ -19,6 +19,7 @@ package v1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
// GroupName is the group name for this API.
@ -52,14 +53,15 @@ func AddToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion)
&ExportOptions{},
&GetOptions{},
&DeleteOptions{},
&CreateOptions{},
&UpdateOptions{},
)
scheme.AddConversionFuncs(
Convert_versioned_Event_to_watch_Event,
Convert_versioned_InternalEvent_to_versioned_Event,
Convert_watch_Event_to_versioned_Event,
Convert_versioned_Event_to_versioned_InternalEvent,
)
utilruntime.Must(scheme.AddConversionFuncs(
Convert_v1_WatchEvent_To_watch_Event,
Convert_v1_InternalEvent_To_v1_WatchEvent,
Convert_watch_Event_To_v1_WatchEvent,
Convert_v1_WatchEvent_To_v1_InternalEvent,
))
// Register Unversioned types under their own special group
scheme.AddUnversionedTypes(Unversioned,
&Status{},
@ -70,8 +72,8 @@ func AddToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion)
)
// register manually. This usually goes through the SchemeBuilder, which we cannot use here.
AddConversionFuncs(scheme)
RegisterDefaults(scheme)
utilruntime.Must(AddConversionFuncs(scheme))
utilruntime.Must(RegisterDefaults(scheme))
}
// scheme is the registry for the common types that adhere to the meta v1 API spec.
@ -86,8 +88,10 @@ func init() {
&ExportOptions{},
&GetOptions{},
&DeleteOptions{},
&CreateOptions{},
&UpdateOptions{},
)
// register manually. This usually goes through the SchemeBuilder, which we cannot use here.
RegisterDefaults(scheme)
utilruntime.Must(RegisterDefaults(scheme))
}

View File

@ -106,7 +106,10 @@ func (t *Time) UnmarshalJSON(b []byte) error {
}
var str string
json.Unmarshal(b, &str)
err := json.Unmarshal(b, &str)
if err != nil {
return err
}
pt, err := time.Parse(time.RFC3339, str)
if err != nil {

View File

@ -22,7 +22,7 @@ import (
"testing"
"time"
"github.com/ghodss/yaml"
"sigs.k8s.io/yaml"
)
type TimeHolder struct {
@ -35,8 +35,8 @@ func TestTimeMarshalYAML(t *testing.T) {
result string
}{
{Time{}, "t: null\n"},
{Date(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05Z\n"},
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"},
{Date(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: \"1998-05-05T05:05:05Z\"\n"},
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: \"1998-05-05T05:05:05Z\"\n"},
}
for _, c := range cases {

View File

@ -76,9 +76,10 @@ type ListMeta struct {
// continue may be set if the user set a limit on the number of items returned, and indicates that
// the server has more data available. The value is opaque and may be used to issue another request
// to the endpoint that served this list to retrieve the next set of available objects. Continuing a
// list may not be possible if the server configuration has changed or more than a few minutes have
// passed. The resourceVersion field returned when using this continue value will be identical to
// the value in the first response.
// consistent list may not be possible if the server configuration has changed or more than a few
// minutes have passed. The resourceVersion field returned when using this continue value will be
// identical to the value in the first response, unless you have received this token from an error
// message.
Continue string `json:"continue,omitempty" protobuf:"bytes,3,opt,name=continue"`
}
@ -285,8 +286,8 @@ const (
)
// OwnerReference contains enough information to let you identify an owning
// object. Currently, an owning object must be in the same namespace, so there
// is no namespace field.
// object. An owning object must be in the same namespace as the dependent, or
// be cluster-scoped, so there is no namespace field.
type OwnerReference struct {
// API version of the referent.
APIVersion string `json:"apiVersion" protobuf:"bytes,5,opt,name=apiVersion"`
@ -363,14 +364,20 @@ type ListOptions struct {
// updated during a chunked list the version of the object that was present at the time the first list
// result was calculated is returned.
Limit int64 `json:"limit,omitempty" protobuf:"varint,7,opt,name=limit"`
// The continue option should be set when retrieving more results from the server. Since this value
// is server defined, clients may only use the continue value from a previous query result with
// identical query parameters (except for the value of continue) and the server may reject a continue
// value it does not recognize. If the specified continue value is no longer valid whether due to
// expiration (generally five to fifteen minutes) or a configuration change on the server the server
// will respond with a 410 ResourceExpired error indicating the client must restart their list without
// the continue field. This field is not supported when watch is true. Clients may start a watch from
// the last resourceVersion value returned by the server and not miss any modifications.
// The continue option should be set when retrieving more results from the server. Since this value is
// server defined, clients may only use the continue value from a previous query result with identical
// query parameters (except for the value of continue) and the server may reject a continue value it
// does not recognize. If the specified continue value is no longer valid whether due to expiration
// (generally five to fifteen minutes) or a configuration change on the server, the server will
// respond with a 410 ResourceExpired error together with a continue token. If the client needs a
// consistent list, it must restart their list without the continue field. Otherwise, the client may
// send another list request with the token received with the 410 error, the server will respond with
// a list starting from the next key, but from the latest snapshot, which is inconsistent from the
// previous list results - objects that are created, modified, or deleted after the first list request
// will be included in the response, as long as their keys are after the "next key".
//
// This field is not supported when watch is true. Clients may start a watch from the last
// resourceVersion value returned by the server and not miss any modifications.
Continue string `json:"continue,omitempty" protobuf:"bytes,8,opt,name=continue"`
}
@ -418,6 +425,12 @@ const (
DeletePropagationForeground DeletionPropagation = "Foreground"
)
const (
// DryRunAll means to complete all processing stages, but don't
// persist changes to storage.
DryRunAll = "All"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// DeleteOptions may be provided when deleting an API object.
@ -453,6 +466,48 @@ type DeleteOptions struct {
// foreground.
// +optional
PropagationPolicy *DeletionPropagation `json:"propagationPolicy,omitempty" protobuf:"varint,4,opt,name=propagationPolicy"`
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
DryRun []string `json:"dryRun,omitempty" protobuf:"bytes,5,rep,name=dryRun"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CreateOptions may be provided when creating an API object.
type CreateOptions struct {
TypeMeta `json:",inline"`
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
DryRun []string `json:"dryRun,omitempty" protobuf:"bytes,1,rep,name=dryRun"`
// If IncludeUninitialized is specified, the object may be
// returned without completing initialization.
IncludeUninitialized bool `json:"includeUninitialized,omitempty" protobuf:"varint,2,opt,name=includeUninitialized"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// UpdateOptions may be provided when updating an API object.
type UpdateOptions struct {
TypeMeta `json:",inline"`
// When present, indicates that modifications should not be
// persisted. An invalid or unrecognized dryRun directive will
// result in an error response and no further processing of the
// request. Valid values are:
// - All: all dry run stages will be processed
// +optional
DryRun []string `json:"dryRun,omitempty" protobuf:"bytes,1,rep,name=dryRun"`
}
// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.
@ -799,7 +854,8 @@ type APIGroup struct {
// The server returns only those CIDRs that it thinks that the client can match.
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP.
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.
ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs" protobuf:"bytes,4,rep,name=serverAddressByClientCIDRs"`
// +optional
ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs,omitempty" protobuf:"bytes,4,rep,name=serverAddressByClientCIDRs"`
}
// ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.

View File

@ -1,5 +1,5 @@
/*
Copyright 2016 The Kubernetes Authors.
Copyright 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.
@ -26,7 +26,7 @@ package v1
//
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
// AUTO-GENERATED FUNCTIONS START HERE
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
var map_APIGroup = map[string]string{
"": "APIGroup contains the name, the supported versions, and the preferred version of a group.",
"name": "name is the name of the group.",
@ -85,12 +85,23 @@ func (APIVersions) SwaggerDoc() map[string]string {
return map_APIVersions
}
var map_CreateOptions = map[string]string{
"": "CreateOptions may be provided when creating an API object.",
"dryRun": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
"includeUninitialized": "If IncludeUninitialized is specified, the object may be returned without completing initialization.",
}
func (CreateOptions) SwaggerDoc() map[string]string {
return map_CreateOptions
}
var map_DeleteOptions = map[string]string{
"": "DeleteOptions may be provided when deleting an API object.",
"gracePeriodSeconds": "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.",
"preconditions": "Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned.",
"orphanDependents": "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.",
"propagationPolicy": "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.",
"dryRun": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
}
func (DeleteOptions) SwaggerDoc() map[string]string {
@ -181,7 +192,7 @@ var map_ListMeta = map[string]string{
"": "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.",
"selfLink": "selfLink is a URL representing this object. Populated by the system. Read-only.",
"resourceVersion": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency",
"continue": "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response.",
"continue": "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.",
}
func (ListMeta) SwaggerDoc() map[string]string {
@ -197,7 +208,7 @@ var map_ListOptions = map[string]string{
"resourceVersion": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.",
"timeoutSeconds": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.",
"limit": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.",
"continue": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server the server will respond with a 410 ResourceExpired error indicating the client must restart their list without the continue field. This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.",
"continue": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.",
}
func (ListOptions) SwaggerDoc() map[string]string {
@ -229,7 +240,7 @@ func (ObjectMeta) SwaggerDoc() map[string]string {
}
var map_OwnerReference = map[string]string{
"": "OwnerReference contains enough information to let you identify an owning object. Currently, an owning object must be in the same namespace, so there is no namespace field.",
"": "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.",
"apiVersion": "API version of the referent.",
"kind": "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"name": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
@ -327,4 +338,13 @@ func (TypeMeta) SwaggerDoc() map[string]string {
return map_TypeMeta
}
var map_UpdateOptions = map[string]string{
"": "UpdateOptions may be provided when updating an API object.",
"dryRun": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
}
func (UpdateOptions) SwaggerDoc() map[string]string {
return map_UpdateOptions
}
// AUTO-GENERATED FUNCTIONS END HERE

View File

@ -17,14 +17,14 @@ limitations under the License.
package v1
import (
"encoding/json"
gojson "encoding/json"
"reflect"
"testing"
jsoniter "github.com/json-iterator/go"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
)
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
func TestVerbsMarshalJSON(t *testing.T) {
cases := []struct {
input APIResource
result string
@ -35,7 +35,7 @@ func TestVerbsUgorjiMarshalJSON(t *testing.T) {
}
for i, c := range cases {
result, err := json.Marshal(&c.input)
result, err := gojson.Marshal(&c.input)
if err != nil {
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
}
@ -45,7 +45,7 @@ func TestVerbsUgorjiMarshalJSON(t *testing.T) {
}
}
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
func TestVerbsJsonIterUnmarshalJSON(t *testing.T) {
cases := []struct {
input string
result APIResource
@ -56,9 +56,10 @@ func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
}
iter := json.CaseSensitiveJsonIterator()
for i, c := range cases {
var result APIResource
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(c.input), &result); err != nil {
if err := iter.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
}
if !reflect.DeepEqual(result, c.result) {
@ -67,8 +68,8 @@ func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
}
}
// TestUgorjiMarshalJSONWithOmit tests that we don't have regressions regarding nil and empty slices with "omit"
func TestUgorjiMarshalJSONWithOmit(t *testing.T) {
// TestMarshalJSONWithOmit tests that we don't have regressions regarding nil and empty slices with "omit"
func TestMarshalJSONWithOmit(t *testing.T) {
cases := []struct {
input LabelSelector
result string
@ -79,7 +80,7 @@ func TestUgorjiMarshalJSONWithOmit(t *testing.T) {
}
for i, c := range cases {
result, err := json.Marshal(&c.input)
result, err := gojson.Marshal(&c.input)
if err != nil {
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
}
@ -102,7 +103,7 @@ func TestVerbsUnmarshalJSON(t *testing.T) {
for i, c := range cases {
var result APIResource
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
if err := gojson.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
}
if !reflect.DeepEqual(result, c.result) {

View File

@ -1,53 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"helpers_test.go",
"unstructured_list_test.go",
],
embed = [":go_default_library"],
deps = [
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"helpers.go",
"unstructured.go",
"unstructured_list.go",
"zz_generated.deepcopy.go",
],
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -18,7 +18,6 @@ package unstructured
import (
gojson "encoding/json"
"errors"
"fmt"
"io"
"strings"
@ -34,14 +33,17 @@ import (
// Returns false if the value is missing.
// No error is returned for a nil field.
func NestedFieldCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return nil, found, err
}
return runtime.DeepCopyJSONValue(val), true, nil
}
func nestedFieldNoCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
// NestedFieldNoCopy returns a reference to a nested field.
// Returns false if value is not found and an error if unable
// to traverse obj.
func NestedFieldNoCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
var val interface{} = obj
for i, field := range fields {
@ -60,7 +62,7 @@ func nestedFieldNoCopy(obj map[string]interface{}, fields ...string) (interface{
// NestedString returns the string value of a nested field.
// Returns false if value is not found and an error if not a string.
func NestedString(obj map[string]interface{}, fields ...string) (string, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return "", found, err
}
@ -74,7 +76,7 @@ func NestedString(obj map[string]interface{}, fields ...string) (string, bool, e
// NestedBool returns the bool value of a nested field.
// Returns false if value is not found and an error if not a bool.
func NestedBool(obj map[string]interface{}, fields ...string) (bool, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return false, found, err
}
@ -88,7 +90,7 @@ func NestedBool(obj map[string]interface{}, fields ...string) (bool, bool, error
// NestedFloat64 returns the float64 value of a nested field.
// Returns false if value is not found and an error if not a float64.
func NestedFloat64(obj map[string]interface{}, fields ...string) (float64, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return 0, found, err
}
@ -102,7 +104,7 @@ func NestedFloat64(obj map[string]interface{}, fields ...string) (float64, bool,
// NestedInt64 returns the int64 value of a nested field.
// Returns false if value is not found and an error if not an int64.
func NestedInt64(obj map[string]interface{}, fields ...string) (int64, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return 0, found, err
}
@ -116,7 +118,7 @@ func NestedInt64(obj map[string]interface{}, fields ...string) (int64, bool, err
// NestedStringSlice returns a copy of []string value of a nested field.
// Returns false if value is not found and an error if not a []interface{} or contains non-string items in the slice.
func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return nil, found, err
}
@ -138,7 +140,7 @@ func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string,
// NestedSlice returns a deep copy of []interface{} value of a nested field.
// Returns false if value is not found and an error if not a []interface{}.
func NestedSlice(obj map[string]interface{}, fields ...string) ([]interface{}, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return nil, found, err
}
@ -180,7 +182,7 @@ func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interfa
// nestedMapNoCopy returns a map[string]interface{} value of a nested field.
// Returns false if value is not found and an error if not a map[string]interface{}.
func nestedMapNoCopy(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) {
val, found, err := nestedFieldNoCopy(obj, fields...)
val, found, err := NestedFieldNoCopy(obj, fields...)
if !found || err != nil {
return nil, found, err
}
@ -433,43 +435,17 @@ func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList
return nil
}
// UnstructuredObjectConverter is an ObjectConverter for use with
// Unstructured objects. Since it has no schema or type information,
// it will only succeed for no-op conversions. This is provided as a
// sane implementation for APIs that require an object converter.
type UnstructuredObjectConverter struct{}
func (UnstructuredObjectConverter) Convert(in, out, context interface{}) error {
unstructIn, ok := in.(*Unstructured)
if !ok {
return fmt.Errorf("input type %T in not valid for unstructured conversion", in)
}
unstructOut, ok := out.(*Unstructured)
if !ok {
return fmt.Errorf("output type %T in not valid for unstructured conversion", out)
}
// maybe deep copy the map? It is documented in the
// ObjectConverter interface that this function is not
// guaranteed to not mutate the input. Or maybe set the input
// object to nil.
unstructOut.Object = unstructIn.Object
return nil
type JSONFallbackEncoder struct {
runtime.Encoder
}
func (UnstructuredObjectConverter) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) {
if kind := in.GetObjectKind().GroupVersionKind(); !kind.Empty() {
gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{kind})
if !ok {
// TODO: should this be a typed error?
return nil, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", kind, target)
func (c JSONFallbackEncoder) Encode(obj runtime.Object, w io.Writer) error {
err := c.Encoder.Encode(obj, w)
if runtime.IsNotRegisteredError(err) {
switch obj.(type) {
case *Unstructured, *UnstructuredList:
return UnstructuredJSONScheme.Encode(obj, w)
}
in.GetObjectKind().SetGroupVersionKind(gvk)
}
return in, nil
}
func (UnstructuredObjectConverter) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
return "", "", errors.New("unstructured cannot convert field labels")
return err
}

View File

@ -58,3 +58,79 @@ func TestRemoveNestedField(t *testing.T) {
RemoveNestedField(obj, "x") // Remove of a non-existent field
assert.Empty(t, obj)
}
func TestNestedFieldNoCopy(t *testing.T) {
target := map[string]interface{}{"foo": "bar"}
obj := map[string]interface{}{
"a": map[string]interface{}{
"b": target,
"c": nil,
"d": []interface{}{"foo"},
},
}
// case 1: field exists and is non-nil
res, exists, err := NestedFieldNoCopy(obj, "a", "b")
assert.True(t, exists)
assert.Nil(t, err)
assert.Equal(t, target, res)
target["foo"] = "baz"
assert.Equal(t, target["foo"], res.(map[string]interface{})["foo"], "result should be a reference to the expected item")
// case 2: field exists and is nil
res, exists, err = NestedFieldNoCopy(obj, "a", "c")
assert.True(t, exists)
assert.Nil(t, err)
assert.Nil(t, res)
// case 3: error traversing obj
res, exists, err = NestedFieldNoCopy(obj, "a", "d", "foo")
assert.False(t, exists)
assert.NotNil(t, err)
assert.Nil(t, res)
// case 4: field does not exist
res, exists, err = NestedFieldNoCopy(obj, "a", "e")
assert.False(t, exists)
assert.Nil(t, err)
assert.Nil(t, res)
}
func TestNestedFieldCopy(t *testing.T) {
target := map[string]interface{}{"foo": "bar"}
obj := map[string]interface{}{
"a": map[string]interface{}{
"b": target,
"c": nil,
"d": []interface{}{"foo"},
},
}
// case 1: field exists and is non-nil
res, exists, err := NestedFieldCopy(obj, "a", "b")
assert.True(t, exists)
assert.Nil(t, err)
assert.Equal(t, target, res)
target["foo"] = "baz"
assert.NotEqual(t, target["foo"], res.(map[string]interface{})["foo"], "result should be a copy of the expected item")
// case 2: field exists and is nil
res, exists, err = NestedFieldCopy(obj, "a", "c")
assert.True(t, exists)
assert.Nil(t, err)
assert.Nil(t, res)
// case 3: error traversing obj
res, exists, err = NestedFieldCopy(obj, "a", "d", "foo")
assert.False(t, exists)
assert.NotNil(t, err)
assert.Nil(t, res)
// case 4: field does not exist
res, exists, err = NestedFieldCopy(obj, "a", "e")
assert.False(t, exists)
assert.Nil(t, err)
assert.Nil(t, res)
}

View File

@ -58,6 +58,26 @@ func (obj *Unstructured) IsList() bool {
_, ok = field.([]interface{})
return ok
}
func (obj *Unstructured) ToList() (*UnstructuredList, error) {
if !obj.IsList() {
// return an empty list back
return &UnstructuredList{Object: obj.Object}, nil
}
ret := &UnstructuredList{}
ret.Object = obj.Object
err := obj.EachListItem(func(item runtime.Object) error {
castItem := item.(*Unstructured)
ret.Items = append(ret.Items, *castItem)
return nil
})
if err != nil {
return nil, err
}
return ret, nil
}
func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
field, ok := obj.Object["items"]
@ -82,7 +102,7 @@ func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
if obj.Object == nil {
obj.Object = make(map[string]interface{})
return make(map[string]interface{})
}
return obj.Object
}
@ -138,7 +158,7 @@ func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
}
func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
field, found, err := nestedFieldNoCopy(u.Object, "metadata", "ownerReferences")
field, found, err := NestedFieldNoCopy(u.Object, "metadata", "ownerReferences")
if !found || err != nil {
return nil
}
@ -159,6 +179,11 @@ func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
}
func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
if references == nil {
RemoveNestedField(u.Object, "metadata", "ownerReferences")
return
}
newReferences := make([]interface{}, 0, len(references))
for _, reference := range references {
out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
@ -192,6 +217,10 @@ func (u *Unstructured) GetNamespace() string {
}
func (u *Unstructured) SetNamespace(namespace string) {
if len(namespace) == 0 {
RemoveNestedField(u.Object, "metadata", "namespace")
return
}
u.setNestedField(namespace, "metadata", "namespace")
}
@ -200,6 +229,10 @@ func (u *Unstructured) GetName() string {
}
func (u *Unstructured) SetName(name string) {
if len(name) == 0 {
RemoveNestedField(u.Object, "metadata", "name")
return
}
u.setNestedField(name, "metadata", "name")
}
@ -207,8 +240,12 @@ func (u *Unstructured) GetGenerateName() string {
return getNestedString(u.Object, "metadata", "generateName")
}
func (u *Unstructured) SetGenerateName(name string) {
u.setNestedField(name, "metadata", "generateName")
func (u *Unstructured) SetGenerateName(generateName string) {
if len(generateName) == 0 {
RemoveNestedField(u.Object, "metadata", "generateName")
return
}
u.setNestedField(generateName, "metadata", "generateName")
}
func (u *Unstructured) GetUID() types.UID {
@ -216,6 +253,10 @@ func (u *Unstructured) GetUID() types.UID {
}
func (u *Unstructured) SetUID(uid types.UID) {
if len(string(uid)) == 0 {
RemoveNestedField(u.Object, "metadata", "uid")
return
}
u.setNestedField(string(uid), "metadata", "uid")
}
@ -223,8 +264,12 @@ func (u *Unstructured) GetResourceVersion() string {
return getNestedString(u.Object, "metadata", "resourceVersion")
}
func (u *Unstructured) SetResourceVersion(version string) {
u.setNestedField(version, "metadata", "resourceVersion")
func (u *Unstructured) SetResourceVersion(resourceVersion string) {
if len(resourceVersion) == 0 {
RemoveNestedField(u.Object, "metadata", "resourceVersion")
return
}
u.setNestedField(resourceVersion, "metadata", "resourceVersion")
}
func (u *Unstructured) GetGeneration() int64 {
@ -236,6 +281,10 @@ func (u *Unstructured) GetGeneration() int64 {
}
func (u *Unstructured) SetGeneration(generation int64) {
if generation == 0 {
RemoveNestedField(u.Object, "metadata", "generation")
return
}
u.setNestedField(generation, "metadata", "generation")
}
@ -244,6 +293,10 @@ func (u *Unstructured) GetSelfLink() string {
}
func (u *Unstructured) SetSelfLink(selfLink string) {
if len(selfLink) == 0 {
RemoveNestedField(u.Object, "metadata", "selfLink")
return
}
u.setNestedField(selfLink, "metadata", "selfLink")
}
@ -252,6 +305,10 @@ func (u *Unstructured) GetContinue() string {
}
func (u *Unstructured) SetContinue(c string) {
if len(c) == 0 {
RemoveNestedField(u.Object, "metadata", "continue")
return
}
u.setNestedField(c, "metadata", "continue")
}
@ -310,6 +367,10 @@ func (u *Unstructured) GetLabels() map[string]string {
}
func (u *Unstructured) SetLabels(labels map[string]string) {
if labels == nil {
RemoveNestedField(u.Object, "metadata", "labels")
return
}
u.setNestedMap(labels, "metadata", "labels")
}
@ -319,6 +380,10 @@ func (u *Unstructured) GetAnnotations() map[string]string {
}
func (u *Unstructured) SetAnnotations(annotations map[string]string) {
if annotations == nil {
RemoveNestedField(u.Object, "metadata", "annotations")
return
}
u.setNestedMap(annotations, "metadata", "annotations")
}
@ -367,6 +432,10 @@ func (u *Unstructured) GetFinalizers() []string {
}
func (u *Unstructured) SetFinalizers(finalizers []string) {
if finalizers == nil {
RemoveNestedField(u.Object, "metadata", "finalizers")
return
}
u.setNestedSlice(finalizers, "metadata", "finalizers")
}
@ -375,5 +444,9 @@ func (u *Unstructured) GetClusterName() string {
}
func (u *Unstructured) SetClusterName(clusterName string) {
if len(clusterName) == 0 {
RemoveNestedField(u.Object, "metadata", "clusterName")
return
}
u.setNestedField(clusterName, "metadata", "clusterName")
}

View File

@ -53,19 +53,18 @@ func (u *UnstructuredList) EachListItem(fn func(runtime.Object) error) error {
}
// UnstructuredContent returns a map contain an overlay of the Items field onto
// the Object field. Items always overwrites overlay. Changing "items" in the
// returned object will affect items in the underlying Items field, but changing
// the "items" slice itself will have no effect.
// TODO: expose SetUnstructuredContent on runtime.Unstructured that allows
// items to be changed.
// the Object field. Items always overwrites overlay.
func (u *UnstructuredList) UnstructuredContent() map[string]interface{} {
out := u.Object
if out == nil {
out = make(map[string]interface{})
out := make(map[string]interface{}, len(u.Object)+1)
// shallow copy every property
for k, v := range u.Object {
out[k] = v
}
items := make([]interface{}, len(u.Items))
for i, item := range u.Items {
items[i] = item.Object
items[i] = item.UnstructuredContent()
}
out["items"] = items
return out

View File

@ -0,0 +1,162 @@
/*
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.
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 unstructured_test
import (
"math/rand"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
"k8s.io/apimachinery/pkg/api/equality"
metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/diff"
)
func TestNilUnstructuredContent(t *testing.T) {
var u unstructured.Unstructured
uCopy := u.DeepCopy()
content := u.UnstructuredContent()
expContent := make(map[string]interface{})
assert.EqualValues(t, expContent, content)
assert.Equal(t, uCopy, &u)
}
// TestUnstructuredMetadataRoundTrip checks that metadata accessors
// correctly set the metadata for unstructured objects.
// First, it fuzzes an empty ObjectMeta and sets this value as the metadata for an unstructured object.
// Next, it uses metadata accessor methods to set these fuzzed values to another unstructured object.
// Finally, it checks that both the unstructured objects are equal.
func TestUnstructuredMetadataRoundTrip(t *testing.T) {
scheme := runtime.NewScheme()
codecs := serializer.NewCodecFactory(scheme)
seed := rand.Int63()
fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs)
N := 1000
for i := 0; i < N; i++ {
u := &unstructured.Unstructured{Object: map[string]interface{}{}}
uCopy := u.DeepCopy()
metadata := &metav1.ObjectMeta{}
fuzzer.Fuzz(metadata)
if err := setObjectMeta(u, metadata); err != nil {
t.Fatalf("unexpected error setting fuzzed ObjectMeta: %v", err)
}
setObjectMetaUsingAccessors(u, uCopy)
// TODO: remove this special casing when creationTimestamp becomes a pointer.
// Right now, creationTimestamp is a struct (metav1.Time) so omitempty holds no meaning for it.
// However, the current behaviour is to remove the field if it holds an empty struct.
// This special casing exists here because custom marshallers for metav1.Time marshal
// an empty value to "null", which gets converted to nil when converting to an unstructured map by "ToUnstructured".
if err := unstructured.SetNestedField(uCopy.UnstructuredContent(), nil, "metadata", "creationTimestamp"); err != nil {
t.Fatalf("unexpected error setting creationTimestamp as nil: %v", err)
}
if !equality.Semantic.DeepEqual(u, uCopy) {
t.Errorf("diff: %v", diff.ObjectReflectDiff(u, uCopy))
}
}
}
// TestUnstructuredMetadataOmitempty checks that ObjectMeta omitempty
// semantics are enforced for unstructured objects.
// The fuzzing test above should catch these cases but this is here just to be safe.
// Example: the metadata.clusterName field has the omitempty json tag
// so if it is set to it's zero value (""), it should be removed from the metadata map.
func TestUnstructuredMetadataOmitempty(t *testing.T) {
scheme := runtime.NewScheme()
codecs := serializer.NewCodecFactory(scheme)
seed := rand.Int63()
fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs)
// fuzz to make sure we don't miss any function calls below
u := &unstructured.Unstructured{Object: map[string]interface{}{}}
metadata := &metav1.ObjectMeta{}
fuzzer.Fuzz(metadata)
if err := setObjectMeta(u, metadata); err != nil {
t.Fatalf("unexpected error setting fuzzed ObjectMeta: %v", err)
}
// set zero values for all fields in metadata explicitly
// to check that omitempty fields having zero values are never set
u.SetName("")
u.SetGenerateName("")
u.SetNamespace("")
u.SetSelfLink("")
u.SetUID("")
u.SetResourceVersion("")
u.SetGeneration(0)
u.SetCreationTimestamp(metav1.Time{})
u.SetDeletionTimestamp(nil)
u.SetDeletionGracePeriodSeconds(nil)
u.SetLabels(nil)
u.SetAnnotations(nil)
u.SetOwnerReferences(nil)
u.SetInitializers(nil)
u.SetFinalizers(nil)
u.SetClusterName("")
gotMetadata, _, err := unstructured.NestedFieldNoCopy(u.UnstructuredContent(), "metadata")
if err != nil {
t.Error(err)
}
emptyMetadata := make(map[string]interface{})
if !reflect.DeepEqual(gotMetadata, emptyMetadata) {
t.Errorf("expected %v, got %v", emptyMetadata, gotMetadata)
}
}
func setObjectMeta(u *unstructured.Unstructured, objectMeta *metav1.ObjectMeta) error {
if objectMeta == nil {
unstructured.RemoveNestedField(u.UnstructuredContent(), "metadata")
return nil
}
metadata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(objectMeta)
if err != nil {
return err
}
u.UnstructuredContent()["metadata"] = metadata
return nil
}
func setObjectMetaUsingAccessors(u, uCopy *unstructured.Unstructured) {
uCopy.SetName(u.GetName())
uCopy.SetGenerateName(u.GetGenerateName())
uCopy.SetNamespace(u.GetNamespace())
uCopy.SetSelfLink(u.GetSelfLink())
uCopy.SetUID(u.GetUID())
uCopy.SetResourceVersion(u.GetResourceVersion())
uCopy.SetGeneration(u.GetGeneration())
uCopy.SetCreationTimestamp(u.GetCreationTimestamp())
uCopy.SetDeletionTimestamp(u.GetDeletionTimestamp())
uCopy.SetDeletionGracePeriodSeconds(u.GetDeletionGracePeriodSeconds())
uCopy.SetLabels(u.GetLabels())
uCopy.SetAnnotations(u.GetAnnotations())
uCopy.SetOwnerReferences(u.GetOwnerReferences())
uCopy.SetInitializers(u.GetInitializers())
uCopy.SetFinalizers(u.GetFinalizers())
uCopy.SetClusterName(u.GetClusterName())
}

View File

@ -0,0 +1,129 @@
/*
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.
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 unstructuredscheme
import (
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
)
var (
scheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(scheme)
)
// NewUnstructuredNegotiatedSerializer returns a simple, negotiated serializer
func NewUnstructuredNegotiatedSerializer() runtime.NegotiatedSerializer {
return unstructuredNegotiatedSerializer{
scheme: scheme,
typer: NewUnstructuredObjectTyper(),
creator: NewUnstructuredCreator(),
}
}
type unstructuredNegotiatedSerializer struct {
scheme *runtime.Scheme
typer runtime.ObjectTyper
creator runtime.ObjectCreater
}
func (s unstructuredNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo {
return []runtime.SerializerInfo{
{
MediaType: "application/json",
EncodesAsText: true,
Serializer: json.NewSerializer(json.DefaultMetaFactory, s.creator, s.typer, false),
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, s.creator, s.typer, true),
StreamSerializer: &runtime.StreamSerializerInfo{
EncodesAsText: true,
Serializer: json.NewSerializer(json.DefaultMetaFactory, s.creator, s.typer, false),
Framer: json.Framer,
},
},
{
MediaType: "application/yaml",
EncodesAsText: true,
Serializer: json.NewYAMLSerializer(json.DefaultMetaFactory, s.creator, s.typer),
},
}
}
func (s unstructuredNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
return versioning.NewDefaultingCodecForScheme(s.scheme, encoder, nil, gv, nil)
}
func (s unstructuredNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
return versioning.NewDefaultingCodecForScheme(s.scheme, nil, decoder, nil, gv)
}
type unstructuredObjectTyper struct {
}
// NewUnstructuredObjectTyper returns an object typer that can deal with unstructured things
func NewUnstructuredObjectTyper() runtime.ObjectTyper {
return unstructuredObjectTyper{}
}
func (t unstructuredObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
// Delegate for things other than Unstructured.
if _, ok := obj.(runtime.Unstructured); !ok {
return nil, false, fmt.Errorf("cannot type %T", obj)
}
gvk := obj.GetObjectKind().GroupVersionKind()
if len(gvk.Kind) == 0 {
return nil, false, runtime.NewMissingKindErr("object has no kind field ")
}
if len(gvk.Version) == 0 {
return nil, false, runtime.NewMissingVersionErr("object has no apiVersion field")
}
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
}
func (t unstructuredObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool {
return true
}
type unstructuredCreator struct{}
// NewUnstructuredCreator returns a simple object creator that always returns an unstructured
func NewUnstructuredCreator() runtime.ObjectCreater {
return unstructuredCreator{}
}
func (c unstructuredCreator) New(kind schema.GroupVersionKind) (runtime.Object, error) {
ret := &unstructured.Unstructured{}
ret.SetGroupVersionKind(kind)
return ret, nil
}
type unstructuredDefaulter struct {
}
// NewUnstructuredDefaulter returns defaulter suitable for unstructured types that doesn't default anything
func NewUnstructuredDefaulter() runtime.ObjectDefaulter {
return unstructuredDefaulter{}
}
func (d unstructuredDefaulter) Default(in runtime.Object) {
}

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Kubernetes Authors.
Copyright 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,38 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["validation_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["validation.go"],
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1/validation",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

Some files were not shown because too many files have changed in this diff Show More