Merge pull request #26007 from smarterclayton/watch_opt

Automatic merge from submit-queue

Additional optimizations to the encode/decode paths

Builds on top of #25983 with a number of other optimizations.
pull/6/head
k8s-merge-robot 2016-05-28 06:27:00 -07:00
commit e543bd6452
44 changed files with 238 additions and 244 deletions

View File

@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch/versioned"
)
const importPrefix = "k8s.io/kubernetes/pkg/api"
@ -233,6 +234,17 @@ func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
case *v1.Endpoints:
return true, v1.Convert_api_Endpoints_To_v1_Endpoints(a, b, s)
}
case *versioned.Event:
switch b := objB.(type) {
case *versioned.InternalEvent:
return true, versioned.Convert_versioned_Event_to_versioned_InternalEvent(a, b, s)
}
case *versioned.InternalEvent:
switch b := objB.(type) {
case *versioned.Event:
return true, versioned.Convert_versioned_InternalEvent_to_versioned_Event(a, b, s)
}
}
return false, nil
})

View File

@ -57,11 +57,11 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
kind := gvk.Kind
if len(kind) == 0 {
// TODO: this is wrong
gvk, err := Scheme.ObjectKind(obj)
gvks, _, err := Scheme.ObjectKinds(obj)
if err != nil {
return nil, err
}
kind = gvk.Kind
kind = gvks[0].Kind
}
// if the object referenced is actually persisted, we can also get version from meta

View File

@ -40,7 +40,7 @@ func TestGetReference(t *testing.T) {
// when vendoring kube, if you don't force the set of registered versions (like this hack/test-go.sh does)
// then you run into trouble because the types aren't registered in the scheme by anything. This does the
// register manually to allow unit test execution
if _, err := Scheme.ObjectKind(&Pod{}); err != nil {
if _, _, err := Scheme.ObjectKinds(&Pod{}); err != nil {
AddToScheme(Scheme)
}

View File

@ -112,11 +112,11 @@ func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.Obje
if err != nil {
return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err)
}
kind, err := typer.ObjectKind(obj)
kinds, _, err := typer.ObjectKinds(obj)
if err != nil {
return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err)
}
return objectMeta, kind, nil
return objectMeta, kinds[0], nil
}
// NamespaceScopedStrategy has a method to tell if the object must be in a namespace.

View File

@ -37,7 +37,7 @@ import (
func init() {
codecsToTest = append(codecsToTest, func(version unversioned.GroupVersion, item runtime.Object) (runtime.Codec, error) {
s := protobuf.NewSerializer(api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), "application/arbitrary.content.type")
s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type")
return api.Codecs.CodecForVersions(s, s, testapi.ExternalGroupVersions(), nil), nil
})
}
@ -138,7 +138,7 @@ func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) {
items := benchmarkItems()
width := len(items)
s := protobuf.NewSerializer(api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), "application/arbitrary.content.type")
s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type")
encoder := api.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion)
var encoded [][]byte
for i := range items {

View File

@ -365,10 +365,11 @@ func ExternalGroupVersions() []unversioned.GroupVersion {
// Get codec based on runtime.Object
func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
kind, err := api.Scheme.ObjectKind(obj)
kinds, _, err := api.Scheme.ObjectKinds(obj)
if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err)
}
kind := kinds[0]
for _, group := range Groups {
if group.GroupVersion().Group != kind.Group {

View File

@ -195,6 +195,8 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
randomQuantity := func() resource.Quantity {
var q resource.Quantity
c.Fuzz(&q)
// precalc the string for benchmarking purposes
_ = q.String()
return q
}
q.Limits = make(api.ResourceList)

View File

@ -118,7 +118,7 @@ func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (unver
}
object := storage.New()
fqKinds, err := a.group.Typer.ObjectKinds(object)
fqKinds, _, err := a.group.Typer.ObjectKinds(object)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
@ -233,8 +233,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
var versionedList interface{}
if isLister {
list := lister.NewList()
listGVK, err := a.group.Typer.ObjectKind(list)
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.WithKind(listGVK.Kind))
listGVKs, _, err := a.group.Typer.ObjectKinds(list)
if err != nil {
return nil, err
}
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.WithKind(listGVKs[0].Kind))
if err != nil {
return nil, err
}
@ -272,10 +275,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
)
if isGetterWithOptions {
getOptions, getSubpath, _ = getterWithOptions.NewGetOptions()
getOptionsInternalKind, err = a.group.Typer.ObjectKind(getOptions)
getOptionsInternalKinds, _, err := a.group.Typer.ObjectKinds(getOptions)
if err != nil {
return nil, err
}
getOptionsInternalKind = getOptionsInternalKinds[0]
versionedGetOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind(getOptionsInternalKind.Kind))
if err != nil {
return nil, err
@ -300,12 +304,16 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if isConnecter {
connectOptions, connectSubpath, _ = connecter.NewConnectOptions()
if connectOptions != nil {
connectOptionsInternalKind, err = a.group.Typer.ObjectKind(connectOptions)
connectOptionsInternalKinds, _, err := a.group.Typer.ObjectKinds(connectOptions)
if err != nil {
return nil, err
}
connectOptionsInternalKind = connectOptionsInternalKinds[0]
versionedConnectOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind(connectOptionsInternalKind.Kind))
if err != nil {
return nil, err
}
}
}
@ -390,18 +398,26 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
resourcePath := namespacedPath
resourceParams := namespaceParams
itemPathPrefix := gpath.Join(a.prefix, scope.ParamName()) + "/"
itemPath := namespacedPath + "/{name}"
itemPathMiddle := "/" + resource + "/"
nameParams := append(namespaceParams, nameParam)
proxyParams := append(nameParams, pathParam)
itemPathSuffix := ""
if hasSubresource {
itemPath = itemPath + "/" + subresource
itemPathSuffix = "/" + subresource
itemPath = itemPath + itemPathSuffix
resourcePath = itemPath
resourceParams = nameParams
}
apiResource.Name = path
apiResource.Namespaced = true
apiResource.Kind = resourceKind
namer := scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), false}
itemPathFn := func(name, namespace string) string {
return itemPathPrefix + namespace + itemPathMiddle + name + itemPathSuffix
}
namer := scopeNaming{scope, a.group.Linker, itemPathFn, false}
actions = appendIf(actions, action{"LIST", resourcePath, resourceParams, namer}, isLister)
actions = appendIf(actions, action{"POST", resourcePath, resourceParams, namer}, isCreater)
@ -430,7 +446,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
// For ex: LIST all pods in all namespaces by sending a LIST request at /api/apiVersion/pods.
// TODO: more strongly type whether a resource allows these actions on "all namespaces" (bulk delete)
if !hasSubresource {
namer = scopeNaming{scope, a.group.Linker, gpath.Join(a.prefix, itemPath), true}
namer = scopeNaming{scope, a.group.Linker, itemPathFn, true}
actions = appendIf(actions, action{"LIST", resource, params, namer}, isLister)
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resource, params, namer}, allowWatchList)
}
@ -776,7 +792,7 @@ func (n rootScopeNaming) ObjectName(obj runtime.Object) (namespace, name string,
type scopeNaming struct {
scope meta.RESTScope
runtime.SelfLinker
itemPath string
itemPathFn func(name, namespace string) string
allNamespaces bool
}
@ -823,9 +839,8 @@ func (n scopeNaming) GenerateLink(req *restful.Request, obj runtime.Object) (pat
if len(name) == 0 {
return "", "", errEmptyName
}
path = strings.Replace(n.itemPath, "{name}", name, 1)
path = strings.Replace(path, "{"+n.scope.ArgumentName()+"}", namespace, 1)
return path, "", nil
return n.itemPathFn(name, namespace), "", nil
}
// GenerateListLink returns the appropriate path and query to locate a list by its canonical path.

View File

@ -36,7 +36,9 @@ func TestScopeNamingGenerateLink(t *testing.T) {
s := scopeNaming{
meta.RESTScopeNamespace,
selfLinker,
"/api/v1/namespaces/{namespace}/services/{name}",
func(name, namespace string) string {
return "/api/v1/namespaces/" + namespace + "/services/" + name
},
true,
}
service := &api.Service{

View File

@ -23,7 +23,6 @@ import (
"math/rand"
"net/http"
"net/url"
gpath "path"
"strings"
"time"
@ -975,10 +974,11 @@ func finishRequest(timeout time.Duration, fn resultFunc) (result runtime.Object,
// transformDecodeError adds additional information when a decode fails.
func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, gvk *unversioned.GroupVersionKind, body []byte) error {
objGVK, err := typer.ObjectKind(into)
objGVKs, _, err := typer.ObjectKinds(into)
if err != nil {
return err
}
objGVK := objGVKs[0]
if gvk != nil && len(gvk.Kind) > 0 {
return errors.NewBadRequest(fmt.Sprintf("%s in version %q cannot be handled as a %s: %v", gvk.Kind, gvk.Version, objGVK.Kind, baseErr))
}
@ -997,7 +997,7 @@ func setSelfLink(obj runtime.Object, req *restful.Request, namer ScopeNamer) err
newURL := *req.Request.URL
// use only canonical paths
newURL.Path = gpath.Clean(path)
newURL.Path = path
newURL.RawQuery = query
newURL.Fragment = ""

View File

@ -167,18 +167,22 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
flusher.Flush()
var unknown runtime.Unknown
internalEvent := &versioned.InternalEvent{}
buf := &bytes.Buffer{}
ch := s.watching.ResultChan()
for {
select {
case <-cn.CloseNotify():
return
case <-timeoutCh:
return
case event, ok := <-s.watching.ResultChan():
case event, ok := <-ch:
if !ok {
// End of results.
return
}
obj := event.Object
s.fixup(obj)
if err := s.embeddedEncoder.EncodeToStream(obj, buf); err != nil {
@ -186,12 +190,15 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
utilruntime.HandleError(fmt.Errorf("unable to encode watch object: %v", err))
return
}
event.Object = &runtime.Unknown{
Raw: buf.Bytes(),
// ContentType is not required here because we are defaulting to the serializer
// type
}
if err := e.Encode((*versioned.InternalEvent)(&event)); err != nil {
// ContentType is not required here because we are defaulting to the serializer
// type
unknown.Raw = buf.Bytes()
event.Object = &unknown
// the internal event will be versioned by the encoder
*internalEvent = versioned.InternalEvent(event)
if err := e.Encode(internalEvent); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to encode watch object: %v (%#v)", err, e))
// client disconnect.
return
@ -208,14 +215,18 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) {
defer ws.Close()
done := make(chan struct{})
go wsstream.IgnoreReceives(ws, 0)
var unknown runtime.Unknown
internalEvent := &versioned.InternalEvent{}
buf := &bytes.Buffer{}
streamBuf := &bytes.Buffer{}
ch := s.watching.ResultChan()
for {
select {
case <-done:
s.watching.Stop()
return
case event, ok := <-s.watching.ResultChan():
case event, ok := <-ch:
if !ok {
// End of results.
return
@ -227,14 +238,15 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) {
utilruntime.HandleError(fmt.Errorf("unable to encode watch object: %v", err))
return
}
event.Object = &runtime.Unknown{
Raw: buf.Bytes(),
// ContentType is not required here because we are defaulting to the serializer
// type
}
// ContentType is not required here because we are defaulting to the serializer
// type
unknown.Raw = buf.Bytes()
event.Object = &unknown
// the internal event will be versioned by the encoder
internalEvent := versioned.InternalEvent(event)
if err := s.encoder.EncodeToStream(&internalEvent, streamBuf); err != nil {
*internalEvent = versioned.InternalEvent(event)
if err := s.encoder.EncodeToStream(internalEvent, streamBuf); err != nil {
// encoding error
utilruntime.HandleError(fmt.Errorf("unable to encode event: %v", err))
s.watching.Stop()

View File

@ -561,6 +561,7 @@ func benchmarkItems() []api.Pod {
items := make([]api.Pod, 3)
for i := range items {
apiObjectFuzzer.Fuzz(&items[i])
items[i].Spec.InitContainers, items[i].Status.InitContainerStatuses = nil, nil
}
return items
}

View File

@ -210,11 +210,11 @@ func (o objects) Kind(kind unversioned.GroupVersionKind, name string) (runtime.O
}
func (o objects) Add(obj runtime.Object) error {
gvk, err := o.scheme.ObjectKind(obj)
gvks, _, err := o.scheme.ObjectKinds(obj)
if err != nil {
return err
}
kind := gvk.Kind
kind := gvks[0].Kind
switch {
case meta.IsListType(obj):

View File

@ -76,28 +76,15 @@ func NewObjectTyper(resources []*unversioned.APIResourceList) (runtime.ObjectTyp
return ot, nil
}
// ObjectKind returns the group,version,kind of the provided object,
// or an error if the object in not *runtime.Unstructured or has no
// group,version,kind information.
func (ot *ObjectTyper) ObjectKind(obj runtime.Object) (unversioned.GroupVersionKind, error) {
if _, ok := obj.(*runtime.Unstructured); !ok {
return unversioned.GroupVersionKind{}, fmt.Errorf("type %T is invalid for dynamic object typer", obj)
}
return obj.GetObjectKind().GroupVersionKind(), nil
}
// ObjectKinds returns a slice of one element with the
// group,version,kind of the provided object, or an error if the
// object is not *runtime.Unstructured or has no group,version,kind
// information.
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, error) {
gvk, err := ot.ObjectKind(obj)
if err != nil {
return nil, err
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) {
if _, ok := obj.(*runtime.Unstructured); !ok {
return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj)
}
return []unversioned.GroupVersionKind{gvk}, nil
return []unversioned.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
}
// Recognizes returns true if the provided group,version,kind was in
@ -105,15 +92,3 @@ func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersi
func (ot *ObjectTyper) Recognizes(gvk unversioned.GroupVersionKind) bool {
return ot.registered[gvk]
}
// IsUnversioned returns false always because *runtime.Unstructured
// objects should always have group,version,kind information set. ok
// will be true if the object's group,version,kind is registered.
func (ot *ObjectTyper) IsUnversioned(obj runtime.Object) (unversioned bool, ok bool) {
gvk, err := ot.ObjectKind(obj)
if err != nil {
return false, false
}
return false, ot.registered[gvk]
}

View File

@ -43,7 +43,7 @@ var Versions = []string{"v1"}
var Codec runtime.Codec
func init() {
yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, api.Scheme, runtime.ObjectTyperToTyper(api.Scheme))
yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, api.Scheme, api.Scheme)
Codec = versioning.NewCodecForScheme(
api.Scheme,
yamlSerializer,

View File

@ -204,11 +204,11 @@ func (o objects) Kind(kind unversioned.GroupVersionKind, name string) (runtime.O
}
func (o objects) Add(obj runtime.Object) error {
gvk, err := o.scheme.ObjectKind(obj)
gvks, _, err := o.scheme.ObjectKinds(obj)
if err != nil {
return err
}
kind := gvk.Kind
kind := gvks[0].Kind
switch {
case meta.IsListType(obj):

View File

@ -224,11 +224,11 @@ func validateFields(a, b string) bool {
func (c *Client) body(t *testing.T, obj runtime.Object, raw *string) *string {
if obj != nil {
fqKind, err := api.Scheme.ObjectKind(obj)
fqKinds, _, err := api.Scheme.ObjectKinds(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
groupName := fqKind.GroupVersion().Group
groupName := fqKinds[0].GroupVersion().Group
if c.ResourceGroup != "" {
groupName = c.ResourceGroup
}

View File

@ -320,11 +320,11 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
}
return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil
default:
fqKind, err := api.Scheme.ObjectKind(object)
fqKinds, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot get the logs from %v", fqKind)
return nil, fmt.Errorf("cannot get the logs from %v", fqKinds[0])
}
},
}

View File

@ -238,7 +238,11 @@ func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer,
return err
}
mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
gvk, err := typer.ObjectKind(obj)
gvks, _, err := typer.ObjectKinds(obj)
if err != nil {
return err
}
gvk := gvks[0]
mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
if err != nil {
return err

View File

@ -221,8 +221,8 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
}
newRc, ok = obj.(*api.ReplicationController)
if !ok {
if gvk, err := typer.ObjectKind(obj); err == nil {
return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvk)
if gvks, _, err := typer.ObjectKinds(obj); err == nil {
return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvks[0])
}
glog.V(4).Infof("Object %#v is not a ReplicationController", obj)
return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename)
@ -377,11 +377,11 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
if outputFormat != "" {
return f.PrintObject(cmd, mapper, newRc, out)
}
kind, err := api.Scheme.ObjectKind(newRc)
kinds, _, err := api.Scheme.ObjectKinds(newRc)
if err != nil {
return err
}
_, res := meta.KindToResource(kind)
_, res := meta.KindToResource(kinds[0])
cmdutil.PrintSuccess(mapper, false, out, res.Resource, oldName, message)
return nil
}

View File

@ -443,10 +443,11 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
}
mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
groupVersionKind, err := typer.ObjectKind(obj)
groupVersionKinds, _, err := typer.ObjectKinds(obj)
if err != nil {
return nil, "", nil, nil, err
}
groupVersionKind := groupVersionKinds[0]
if len(overrides) > 0 {
codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))

View File

@ -427,11 +427,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
}
return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return "", err
}
return "", fmt.Errorf("cannot extract pod selector from %v", gvk)
return "", fmt.Errorf("cannot extract pod selector from %v", gvks[0])
}
},
PortsForObject: func(object runtime.Object) ([]string, error) {
@ -448,11 +448,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *extensions.ReplicaSet:
return getPorts(t.Spec.Template.Spec), nil
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot extract ports from %v", gvk)
return nil, fmt.Errorf("cannot extract ports from %v", gvks[0])
}
},
ProtocolsForObject: func(object runtime.Object) (map[string]string, error) {
@ -469,11 +469,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *extensions.ReplicaSet:
return getProtocols(t.Spec.Template.Spec), nil
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot extract protocols from %v", gvk)
return nil, fmt.Errorf("cannot extract protocols from %v", gvks[0])
}
},
LabelsForObject: func(object runtime.Object) (map[string]string, error) {
@ -531,11 +531,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return c.Pods(pod.Namespace).GetLogs(pod.Name, opts), nil
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot get the logs from %v", gvk)
return nil, fmt.Errorf("cannot get the logs from %v", gvks[0])
}
},
PauseObject: func(object runtime.Object) (bool, error) {
@ -553,11 +553,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
_, err := c.Extensions().Deployments(t.Namespace).Update(t)
return false, err
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return false, err
}
return false, fmt.Errorf("cannot pause %v", gvk)
return false, fmt.Errorf("cannot pause %v", gvks[0])
}
},
ResumeObject: func(object runtime.Object) (bool, error) {
@ -575,11 +575,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
_, err := c.Extensions().Deployments(t.Namespace).Update(t)
return false, err
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return false, err
}
return false, fmt.Errorf("cannot resume %v", gvk)
return false, fmt.Errorf("cannot resume %v", gvks[0])
}
},
Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
@ -712,11 +712,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *api.Pod:
return t, nil
default:
gvk, err := api.Scheme.ObjectKind(object)
gvks, _, err := api.Scheme.ObjectKinds(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk)
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvks[0])
}
},
// UpdatePodSpecForObject update the pod specification for the provided object
@ -1101,12 +1101,12 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
// PrintObject prints an api object given command line flags to modify the output format
func (f *Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
gvk, err := api.Scheme.ObjectKind(obj)
gvks, _, err := api.Scheme.ObjectKinds(obj)
if err != nil {
return err
}
mapping, err := mapper.RESTMapping(gvk.GroupKind())
mapping, err := mapper.RESTMapping(gvks[0].GroupKind())
if err != nil {
return err
}

View File

@ -96,7 +96,7 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
// if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object, preferredGVKs []unversioned.GroupVersionKind) (*Info, error) {
groupVersionKinds, err := m.ObjectKinds(obj)
groupVersionKinds, _, err := m.ObjectKinds(obj)
if err != nil {
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
}

View File

@ -251,7 +251,7 @@ func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder
// objects that are not part of api.Scheme must be converted to JSON
// TODO: convert to map[string]interface{}, attach to runtime.Unknown?
if !version.IsEmpty() {
if _, err := api.Scheme.ObjectKind(info.Object); runtime.IsNotRegisteredError(err) {
if _, _, err := api.Scheme.ObjectKinds(info.Object); runtime.IsNotRegisteredError(err) {
// TODO: ideally this would encode to version, but we don't expose multiple codecs here.
data, err := runtime.Encode(encoder, info.Object)
if err != nil {

View File

@ -69,7 +69,8 @@ func GetPrinter(format, formatArgument string) (ResourcePrinter, bool, error) {
printer = &YAMLPrinter{}
case "name":
printer = &NamePrinter{
Typer: runtime.ObjectTyperToTyper(api.Scheme),
// TODO: this is wrong, these should be provided as an argument to GetPrinter
Typer: api.Scheme,
Decoder: api.Codecs.UniversalDecoder(),
}
case "template", "go-template":
@ -203,14 +204,12 @@ func (p *VersionedPrinter) HandledResources() []string {
// NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
type NamePrinter struct {
Decoder runtime.Decoder
Typer runtime.Typer
Typer runtime.ObjectTyper
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
// and print "resource/name" pair. If the object is a List, print all items in it.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
gvk, _, _ := p.Typer.ObjectKind(obj)
if meta.IsListType(obj) {
items, err := meta.ExtractList(obj)
if err != nil {
@ -236,10 +235,9 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
}
}
if gvk != nil {
if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
// TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
_, resource := meta.KindToResource(*gvk)
_, resource := meta.KindToResource(gvks[0])
fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
} else {
fmt.Fprintf(w, "<unknown>/%s\n", name)

View File

@ -466,7 +466,7 @@ func TestPrinters(t *testing.T) {
"template2": templatePrinter2,
"jsonpath": jsonpathPrinter,
"name": &NamePrinter{
Typer: runtime.ObjectTyperToTyper(api.Scheme),
Typer: api.Scheme,
Decoder: api.Codecs.UniversalDecoder(),
},
}

View File

@ -152,10 +152,11 @@ func (t *Tester) TestWatch(valid runtime.Object, labelsPass, labelsFail []labels
// =============================================================================
// get codec based on runtime.Object
func getCodec(obj runtime.Object) (runtime.Codec, error) {
fqKind, err := api.Scheme.ObjectKind(obj)
fqKinds, _, err := api.Scheme.ObjectKinds(obj)
if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err)
}
fqKind := fqKinds[0]
// TODO: caesarxuchao: we should detect which group an object belongs to
// by using the version returned by Schem.ObjectVersionAndKind() once we
// split the schemes for internal objects.

View File

@ -78,13 +78,13 @@ func EncodeOrDie(e Encoder, obj Object) string {
// UseOrCreateObject returns obj if the canonical ObjectKind returned by the provided typer matches gvk, or
// invokes the ObjectCreator to instantiate a new gvk. Returns an error if the typer cannot find the object.
func UseOrCreateObject(t Typer, c ObjectCreater, gvk unversioned.GroupVersionKind, obj Object) (Object, error) {
func UseOrCreateObject(t ObjectTyper, c ObjectCreater, gvk unversioned.GroupVersionKind, obj Object) (Object, error) {
if obj != nil {
into, _, err := t.ObjectKind(obj)
into, _, err := t.ObjectKinds(obj)
if err != nil {
return nil, err
}
if gvk == *into {
if gvk == into[0] {
return obj, nil
}
}
@ -116,7 +116,7 @@ func (n NoopDecoder) Decode(data []byte, gvk *unversioned.GroupVersionKind, into
// NewParameterCodec creates a ParameterCodec capable of transforming url values into versioned objects and back.
func NewParameterCodec(scheme *Scheme) ParameterCodec {
return &parameterCodec{
typer: ObjectTyperToTyper(scheme),
typer: scheme,
convertor: scheme,
creator: scheme,
}
@ -124,7 +124,7 @@ func NewParameterCodec(scheme *Scheme) ParameterCodec {
// parameterCodec implements conversion to and from query parameters and objects.
type parameterCodec struct {
typer Typer
typer ObjectTyper
convertor ObjectConvertor
creator ObjectCreater
}
@ -137,10 +137,11 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from unversione
if len(parameters) == 0 {
return nil
}
targetGVK, _, err := c.typer.ObjectKind(into)
targetGVKs, _, err := c.typer.ObjectKinds(into)
if err != nil {
return err
}
targetGVK := targetGVKs[0]
if targetGVK.GroupVersion() == from {
return c.convertor.Convert(&parameters, into)
}
@ -157,10 +158,11 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from unversione
// EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
// Returns an error if conversion is not possible.
func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersion) (url.Values, error) {
gvk, _, err := c.typer.ObjectKind(obj)
gvks, _, err := c.typer.ObjectKinds(obj)
if err != nil {
return nil, err
}
gvk := gvks[0]
if to != gvk.GroupVersion() {
out, err := c.convertor.ConvertToVersion(obj, to)
if err != nil {

View File

@ -26,28 +26,6 @@ import (
"k8s.io/kubernetes/pkg/util/errors"
)
type objectTyperToTyper struct {
typer ObjectTyper
}
func (t objectTyperToTyper) ObjectKind(obj Object) (*unversioned.GroupVersionKind, bool, error) {
gvk, err := t.typer.ObjectKind(obj)
if err != nil {
return nil, false, err
}
unversionedType, ok := t.typer.IsUnversioned(obj)
if !ok {
// ObjectTyper violates its contract
return nil, false, fmt.Errorf("typer returned a kind for %v, but then reported it was not in the scheme with IsUnversioned", reflect.TypeOf(obj))
}
return &gvk, unversionedType, nil
}
// ObjectTyperToTyper casts the old typer interface to the new typer interface
func ObjectTyperToTyper(typer ObjectTyper) Typer {
return objectTyperToTyper{typer: typer}
}
// unsafeObjectConvertor implements ObjectConvertor using the unsafe conversion path.
type unsafeObjectConvertor struct {
*Scheme
@ -195,19 +173,9 @@ type MultiObjectTyper []ObjectTyper
var _ ObjectTyper = MultiObjectTyper{}
func (m MultiObjectTyper) ObjectKind(obj Object) (gvk unversioned.GroupVersionKind, err error) {
func (m MultiObjectTyper) ObjectKinds(obj Object) (gvks []unversioned.GroupVersionKind, unversionedType bool, err error) {
for _, t := range m {
gvk, err = t.ObjectKind(obj)
if err == nil {
return
}
}
return
}
func (m MultiObjectTyper) ObjectKinds(obj Object) (gvks []unversioned.GroupVersionKind, err error) {
for _, t := range m {
gvks, err = t.ObjectKinds(obj)
gvks, unversionedType, err = t.ObjectKinds(obj)
if err == nil {
return
}
@ -224,15 +192,6 @@ func (m MultiObjectTyper) Recognizes(gvk unversioned.GroupVersionKind) bool {
return false
}
func (m MultiObjectTyper) IsUnversioned(obj Object) (bool, bool) {
for _, t := range m {
if unversioned, ok := t.IsUnversioned(obj); ok {
return unversioned, true
}
}
return false, false
}
// SetZeroValue would set the object of objPtr to zero value of its type.
func SetZeroValue(objPtr Object) error {
v, err := conversion.EnforcePtr(objPtr)

View File

@ -30,15 +30,6 @@ const (
APIVersionInternal = "__internal"
)
// Typer retrieves information about an object's group, version, and kind.
type Typer interface {
// ObjectKind returns the version and kind of the provided object, or an
// error if the object is not recognized (IsNotRegisteredError will return true).
// It returns whether the object is considered unversioned at the same time.
// TODO: align the signature of ObjectTyper with this interface
ObjectKind(Object) (*unversioned.GroupVersionKind, bool, error)
}
type Encoder interface {
// EncodeToStream writes an object to a stream. Override versions may be provided for each group
// that enforce a certain versioning. Implementations may return errors if the versions are incompatible,
@ -178,20 +169,14 @@ type ObjectConvertor interface {
// ObjectTyper contains methods for extracting the APIVersion and Kind
// of objects.
type ObjectTyper interface {
// ObjectKind returns the default group,version,kind of the provided object, or an
// error if the object is not recognized (IsNotRegisteredError will return true).
ObjectKind(Object) (unversioned.GroupVersionKind, error)
// ObjectKinds returns the all possible group,version,kind of the provided object, or an
// error if the object is not recognized (IsNotRegisteredError will return true).
ObjectKinds(Object) ([]unversioned.GroupVersionKind, error)
// ObjectKinds returns the all possible group,version,kind of the provided object, true if
// the object is unversioned, or an error if the object is not recognized
// (IsNotRegisteredError will return true).
ObjectKinds(Object) ([]unversioned.GroupVersionKind, bool, error)
// Recognizes returns true if the scheme is able to handle the provided version and kind,
// or more precisely that the provided version is a possible conversion or decoding
// target.
Recognizes(gvk unversioned.GroupVersionKind) bool
// IsUnversioned returns true if the provided object is considered unversioned and thus
// should have Version and Group suppressed in the output. If the object is not recognized
// in the scheme, ok is false.
IsUnversioned(Object) (unversioned bool, ok bool)
}
// ObjectCreater contains methods for instantiating an object by kind and version.

View File

@ -211,31 +211,32 @@ func (s *Scheme) KnownTypes(gv unversioned.GroupVersion) map[string]reflect.Type
return types
}
// ObjectKind returns the group,version,kind of the go object,
// or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKind(obj Object) (unversioned.GroupVersionKind, error) {
gvks, err := s.ObjectKinds(obj)
// ObjectKind returns the group,version,kind of the go object and true if this object
// is considered unversioned, or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKind(obj Object) (unversioned.GroupVersionKind, bool, error) {
gvks, unversionedType, err := s.ObjectKinds(obj)
if err != nil {
return unversioned.GroupVersionKind{}, err
return unversioned.GroupVersionKind{}, false, err
}
return gvks[0], nil
return gvks[0], unversionedType, nil
}
// ObjectKinds returns all possible group,version,kind of the go object,
// or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKinds(obj Object) ([]unversioned.GroupVersionKind, error) {
// ObjectKinds returns all possible group,version,kind of the go object, true if the
// object is considered unversioned, or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKinds(obj Object) ([]unversioned.GroupVersionKind, bool, error) {
v, err := conversion.EnforcePtr(obj)
if err != nil {
return nil, err
return nil, false, err
}
t := v.Type()
gvks, ok := s.typeToGVK[t]
if !ok {
return nil, &notRegisteredErr{t: t}
return nil, false, &notRegisteredErr{t: t}
}
_, unversionedType := s.unversionedTypes[t]
return gvks, nil
return gvks, unversionedType, nil
}
// Recognizes returns true if the scheme is able to handle the provided group,version,kind
@ -439,13 +440,13 @@ func (s *Scheme) Convert(in, out interface{}) error {
inVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
outVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
if inObj, ok := in.(Object); ok {
if gvk, err := s.ObjectKind(inObj); err == nil {
inVersion = gvk.GroupVersion()
if gvks, _, err := s.ObjectKinds(inObj); err == nil {
inVersion = gvks[0].GroupVersion()
}
}
if outObj, ok := out.(Object); ok {
if gvk, err := s.ObjectKind(outObj); err == nil {
outVersion = gvk.GroupVersion()
if gvks, _, err := s.ObjectKinds(outObj); err == nil {
outVersion = gvks[0].GroupVersion()
}
}
flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
@ -504,7 +505,7 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion unversioned.GroupVersion
outKind := outVersion.WithKind(kind.Kind)
inKind, err := s.ObjectKind(in)
inKinds, _, err := s.ObjectKinds(in)
if err != nil {
return nil, err
}
@ -514,7 +515,7 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion unversioned.GroupVersion
return nil, err
}
flags, meta := s.generateConvertMeta(inKind.GroupVersion(), outVersion, in)
flags, meta := s.generateConvertMeta(inKinds[0].GroupVersion(), outVersion, in)
if err := s.converter.Convert(in, out, flags, meta); err != nil {
return nil, err
}
@ -603,8 +604,11 @@ func setTargetVersion(obj Object, raw *Scheme, gv unversioned.GroupVersion) {
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
return
}
gvk, _ := raw.ObjectKind(obj)
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind})
if gvks, _, _ := raw.ObjectKinds(obj); len(gvks) > 0 {
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvks[0].Kind})
} else {
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version})
}
}
// setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.

View File

@ -354,10 +354,11 @@ func TestUnversionedTypes(t *testing.T) {
t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok)
}
kind, err := scheme.ObjectKind(&InternalSimple{})
kinds, _, err := scheme.ObjectKinds(&InternalSimple{})
if err != nil {
t.Fatal(err)
}
kind := kinds[0]
if kind != externalGV.WithKind("InternalSimple") {
t.Fatalf("unexpected: %#v", kind)
}

View File

@ -58,9 +58,9 @@ type serializerType struct {
}
func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory) []serializerType {
jsonSerializer := json.NewSerializer(mf, scheme, runtime.ObjectTyperToTyper(scheme), false)
jsonPrettySerializer := json.NewSerializer(mf, scheme, runtime.ObjectTyperToTyper(scheme), true)
yamlSerializer := json.NewYAMLSerializer(mf, scheme, runtime.ObjectTyperToTyper(scheme))
jsonSerializer := json.NewSerializer(mf, scheme, scheme, false)
jsonPrettySerializer := json.NewSerializer(mf, scheme, scheme, true)
yamlSerializer := json.NewYAMLSerializer(mf, scheme, scheme)
serializers := []serializerType{
{

View File

@ -31,7 +31,7 @@ import (
// NewSerializer creates a JSON serializer that handles encoding versioned objects into the proper JSON form. If typer
// is not nil, the object has the group, version, and kind fields set.
func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.Typer, pretty bool) *Serializer {
func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer {
return &Serializer{
meta: meta,
creater: creater,
@ -44,7 +44,7 @@ func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtim
// NewYAMLSerializer creates a YAML serializer that handles encoding versioned objects into the proper YAML form. If typer
// is not nil, the object has the group, version, and kind fields set. This serializer supports only the subset of YAML that
// matches JSON, and will error if constructs are used that do not serialize to JSON.
func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.Typer) *Serializer {
func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer {
return &Serializer{
meta: meta,
creater: creater,
@ -56,7 +56,7 @@ func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer ru
type Serializer struct {
meta MetaFactory
creater runtime.ObjectCreater
typer runtime.Typer
typer runtime.ObjectTyper
yaml bool
pretty bool
}
@ -116,7 +116,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
}
if into != nil {
typed, _, err := s.typer.ObjectKind(into)
types, _, err := s.typer.ObjectKinds(into)
switch {
case runtime.IsNotRegisteredError(err):
if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(into); err != nil {
@ -126,6 +126,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
case err != nil:
return nil, actual, err
default:
typed := types[0]
if len(actual.Kind) == 0 {
actual.Kind = typed.Kind
}

View File

@ -41,7 +41,7 @@ func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind {
func TestDecode(t *testing.T) {
testCases := []struct {
creater runtime.ObjectCreater
typer runtime.Typer
typer runtime.ObjectTyper
yaml bool
pretty bool
@ -260,6 +260,13 @@ type mockTyper struct {
err error
}
func (t *mockTyper) ObjectKind(obj runtime.Object) (*unversioned.GroupVersionKind, bool, error) {
return t.gvk, false, t.err
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) {
if t.gvk == nil {
return nil, false, t.err
}
return []unversioned.GroupVersionKind{*t.gvk}, false, t.err
}
func (t *mockTyper) Recognizes(_ unversioned.GroupVersionKind) bool {
return false
}

View File

@ -59,7 +59,7 @@ func IsNotMarshalable(err error) bool {
// as-is (any type info passed with the object will be used).
//
// This encoding scheme is experimental, and is subject to change at any time.
func NewSerializer(creater runtime.ObjectCreater, typer runtime.Typer, defaultContentType string) *Serializer {
func NewSerializer(creater runtime.ObjectCreater, typer runtime.ObjectTyper, defaultContentType string) *Serializer {
return &Serializer{
prefix: protoEncodingPrefix,
creater: creater,
@ -71,7 +71,7 @@ func NewSerializer(creater runtime.ObjectCreater, typer runtime.Typer, defaultCo
type Serializer struct {
prefix []byte
creater runtime.ObjectCreater
typer runtime.Typer
typer runtime.ObjectTyper
contentType string
}
@ -131,7 +131,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
}
if into != nil {
typed, _, err := s.typer.ObjectKind(into)
types, _, err := s.typer.ObjectKinds(into)
switch {
case runtime.IsNotRegisteredError(err):
pb, ok := into.(proto.Message)
@ -145,12 +145,12 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
case err != nil:
return nil, &actual, err
default:
copyKindDefaults(&actual, typed)
copyKindDefaults(&actual, &types[0])
// if the result of defaulting did not set a version or group, ensure that at least group is set
// (copyKindDefaults will not assign Group if version is already set). This guarantees that the group
// of into is set if there is no better information from the caller or object.
if len(actual.Version) == 0 && len(actual.Group) == 0 {
actual.Group = typed.Group
actual.Group = types[0].Group
}
}
}
@ -277,7 +277,7 @@ func estimateUnknownSize(unk *runtime.Unknown, byteSize uint64) uint64 {
// encoded object, and thus is not self describing (callers must know what type is being described in order to decode).
//
// This encoding scheme is experimental, and is subject to change at any time.
func NewRawSerializer(creater runtime.ObjectCreater, typer runtime.Typer, defaultContentType string) *RawSerializer {
func NewRawSerializer(creater runtime.ObjectCreater, typer runtime.ObjectTyper, defaultContentType string) *RawSerializer {
return &RawSerializer{
creater: creater,
typer: typer,
@ -289,7 +289,7 @@ func NewRawSerializer(creater runtime.ObjectCreater, typer runtime.Typer, defaul
// type).
type RawSerializer struct {
creater runtime.ObjectCreater
typer runtime.Typer
typer runtime.ObjectTyper
contentType string
}
@ -337,7 +337,7 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio
return intoUnknown, actual, nil
}
typed, _, err := s.typer.ObjectKind(into)
types, _, err := s.typer.ObjectKinds(into)
switch {
case runtime.IsNotRegisteredError(err):
pb, ok := into.(proto.Message)
@ -351,12 +351,12 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio
case err != nil:
return nil, actual, err
default:
copyKindDefaults(actual, typed)
copyKindDefaults(actual, &types[0])
// if the result of defaulting did not set a version or group, ensure that at least group is set
// (copyKindDefaults will not assign Group if version is already set). This guarantees that the group
// of into is set if there is no better information from the caller or object.
if len(actual.Version) == 0 && len(actual.Group) == 0 {
actual.Group = typed.Group
actual.Group = types[0].Group
}
}
@ -371,7 +371,7 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio
}
// unmarshalToObject is the common code between decode in the raw and normal serializer.
func unmarshalToObject(typer runtime.Typer, creater runtime.ObjectCreater, actual *unversioned.GroupVersionKind, into runtime.Object, data []byte) (runtime.Object, *unversioned.GroupVersionKind, error) {
func unmarshalToObject(typer runtime.ObjectTyper, creater runtime.ObjectCreater, actual *unversioned.GroupVersionKind, into runtime.Object, data []byte) (runtime.Object, *unversioned.GroupVersionKind, error) {
// use the target if necessary
obj, err := runtime.UseOrCreateObject(typer, creater, *actual, into)
if err != nil {

View File

@ -323,7 +323,7 @@ func TestDecodeObjects(t *testing.T) {
}
for i, test := range testCases {
s := protobuf.NewSerializer(api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), "application/protobuf")
s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/protobuf")
obj, err := runtime.Decode(s, test.data)
switch {

View File

@ -31,8 +31,8 @@ const (
)
func protobufSerializer(scheme *runtime.Scheme) (serializerType, bool) {
serializer := protobuf.NewSerializer(scheme, runtime.ObjectTyperToTyper(scheme), contentTypeProtobuf)
raw := protobuf.NewRawSerializer(scheme, runtime.ObjectTyperToTyper(scheme), contentTypeProtobuf)
serializer := protobuf.NewSerializer(scheme, scheme, contentTypeProtobuf)
raw := protobuf.NewRawSerializer(scheme, scheme, contentTypeProtobuf)
return serializerType{
AcceptContentTypes: []string{contentTypeProtobuf},
ContentType: contentTypeProtobuf,

View File

@ -32,8 +32,8 @@ func TestRecognizer(t *testing.T) {
s := runtime.NewScheme()
s.AddKnownTypes(unversioned.GroupVersion{Version: "v1"}, &A{})
d := NewDecoder(
json.NewSerializer(json.DefaultMetaFactory, s, runtime.ObjectTyperToTyper(s), false),
json.NewYAMLSerializer(json.DefaultMetaFactory, s, runtime.ObjectTyperToTyper(s)),
json.NewSerializer(json.DefaultMetaFactory, s, s, false),
json.NewYAMLSerializer(json.DefaultMetaFactory, s, s),
)
out, _, err := d.Decode([]byte(`
kind: A

View File

@ -71,7 +71,7 @@ func NewCodecForScheme(
encodeVersion []unversioned.GroupVersion,
decodeVersion []unversioned.GroupVersion,
) runtime.Codec {
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, runtime.ObjectTyperToTyper(scheme), encodeVersion, decodeVersion)
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, encodeVersion, decodeVersion)
}
// NewCodec takes objects in their internal versions and converts them to external versions before
@ -83,7 +83,7 @@ func NewCodec(
convertor runtime.ObjectConvertor,
creater runtime.ObjectCreater,
copier runtime.ObjectCopier,
typer runtime.Typer,
typer runtime.ObjectTyper,
encodeVersion []unversioned.GroupVersion,
decodeVersion []unversioned.GroupVersion,
) runtime.Codec {
@ -104,6 +104,11 @@ func NewCodec(
}
internal.encodeVersion[v.Group] = v
}
if len(internal.encodeVersion) == 1 {
for _, v := range internal.encodeVersion {
internal.preferredEncodeVersion = []unversioned.GroupVersion{v}
}
}
}
if decodeVersion != nil {
internal.decodeVersion = make(map[string]unversioned.GroupVersion)
@ -125,10 +130,12 @@ type codec struct {
convertor runtime.ObjectConvertor
creater runtime.ObjectCreater
copier runtime.ObjectCopier
typer runtime.Typer
typer runtime.ObjectTyper
encodeVersion map[string]unversioned.GroupVersion
decodeVersion map[string]unversioned.GroupVersion
preferredEncodeVersion []unversioned.GroupVersion
}
// Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is
@ -221,15 +228,16 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
if _, ok := obj.(*runtime.Unknown); ok {
return c.encoder.EncodeToStream(obj, w, overrides...)
}
gvk, isUnversioned, err := c.typer.ObjectKind(obj)
gvks, isUnversioned, err := c.typer.ObjectKinds(obj)
if err != nil {
return err
}
gvk := gvks[0]
if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned {
objectKind := obj.GetObjectKind()
old := objectKind.GroupVersionKind()
objectKind.SetGroupVersionKind(*gvk)
objectKind.SetGroupVersionKind(gvk)
err = c.encoder.EncodeToStream(obj, w, overrides...)
objectKind.SetGroupVersionKind(old)
return err
@ -248,13 +256,16 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
}
// attempt a conversion to the sole encode version
if !ok && len(c.encodeVersion) == 1 {
if !ok && c.preferredEncodeVersion != nil {
ok = true
for _, v := range c.encodeVersion {
targetGV = v
targetGV = c.preferredEncodeVersion[0]
if len(overrides) > 0 {
// ensure the target override is first
overrides = promoteOrPrependGroupVersion(targetGV, overrides)
} else {
// avoids allocating a new array for each call to EncodeToVersion
overrides = c.preferredEncodeVersion
}
// ensure the target override is first
overrides = promoteOrPrependGroupVersion(targetGV, overrides)
}
// if no fallback is available, error

View File

@ -49,7 +49,7 @@ func TestDecode(t *testing.T) {
convertor runtime.ObjectConvertor
creater runtime.ObjectCreater
copier runtime.ObjectCopier
typer runtime.Typer
typer runtime.ObjectTyper
yaml bool
pretty bool

View File

@ -25,6 +25,7 @@ import (
type lengthDelimitedFrameWriter struct {
w io.Writer
h [4]byte
}
func NewLengthDelimitedFrameWriter(w io.Writer) io.Writer {
@ -34,13 +35,12 @@ func NewLengthDelimitedFrameWriter(w io.Writer) io.Writer {
// Write writes a single frame to the nested writer, prepending it with the length in
// in bytes of data (as a 4 byte, bigendian uint32).
func (w *lengthDelimitedFrameWriter) Write(data []byte) (int, error) {
header := [4]byte{}
binary.BigEndian.PutUint32(header[:], uint32(len(data)))
n, err := w.w.Write(header[:])
binary.BigEndian.PutUint32(w.h[:], uint32(len(data)))
n, err := w.w.Write(w.h[:])
if err != nil {
return 0, err
}
if n != len(header) {
if n != len(w.h) {
return 0, io.ErrShortWrite
}
return w.w.Write(data)

View File

@ -42,7 +42,7 @@ var Versions = []string{"v1"}
var Codec runtime.Codec
func init() {
jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), true)
jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, api.Scheme, api.Scheme, true)
Codec = versioning.NewCodecForScheme(
api.Scheme,
jsonSerializer,

View File

@ -59,9 +59,9 @@ func (s *wrappedSerializer) UniversalDeserializer() runtime.Decoder {
}
func (s *wrappedSerializer) EncoderForVersion(encoder runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
return versioning.NewCodec(encoder, nil, s.scheme, s.scheme, s.scheme, runtime.ObjectTyperToTyper(s.scheme), []unversioned.GroupVersion{gv}, nil)
return versioning.NewCodec(encoder, nil, s.scheme, s.scheme, s.scheme, s.scheme, []unversioned.GroupVersion{gv}, nil)
}
func (s *wrappedSerializer) DecoderToVersion(decoder runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
return versioning.NewCodec(nil, decoder, s.scheme, s.scheme, s.scheme, runtime.ObjectTyperToTyper(s.scheme), nil, []unversioned.GroupVersion{gv})
return versioning.NewCodec(nil, decoder, s.scheme, s.scheme, s.scheme, s.scheme, nil, []unversioned.GroupVersion{gv})
}