Merge pull request #55660 from smarterclayton/get_clean

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Stop using VersionedObject in resource.Builder, use unstructured

Remove the need for kubectl callers to distinguish between unstructured and versioned / type aware builders.  The factory should create a single builder than can be set to return unstructured objects.  Callers can then use one of the new helpers on `resource.Info` to convert the objects into the desired form - `Internal()` for printers, `Typed()` for external versions, and `Unstructured()` to ensure the object is in the right state.  Leverages the new scheme support for unstructured conversion so that higher level callers can perform best effort conversion (get typed versions if you have them, otherwise use default behavior).

`get.go` demonstrates this by removing the previous logic that depended on the underlying scheme.  Other commands are updated to be consistent.

Includes #55650 and #55647.

Kubernetes-commit: 40e7101844fd4cce86e3c6df3f7d093d74337418
This commit is contained in:
Kubernetes Publisher 2017-11-20 11:36:34 -08:00
commit b29da5307c
2 changed files with 32 additions and 14 deletions

View File

@ -17,22 +17,28 @@ limitations under the License.
package discovery package discovery
import ( import (
"fmt" "reflect"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
) )
// UnstructuredObjectTyper provides a runtime.ObjectTyper implmentation for // UnstructuredObjectTyper provides a runtime.ObjectTyper implementation for
// runtime.Unstructured object based on discovery information. // runtime.Unstructured object based on discovery information.
type UnstructuredObjectTyper struct { type UnstructuredObjectTyper struct {
registered map[schema.GroupVersionKind]bool registered map[schema.GroupVersionKind]bool
typers []runtime.ObjectTyper
} }
// NewUnstructuredObjectTyper returns a runtime.ObjectTyper for // NewUnstructuredObjectTyper returns a runtime.ObjectTyper for
// unstructred objects based on discovery information. // unstructured objects based on discovery information. It accepts a list of fallback typers
func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *UnstructuredObjectTyper { // for handling objects that are not runtime.Unstructured. It does not delegate the Recognizes
dot := &UnstructuredObjectTyper{registered: make(map[schema.GroupVersionKind]bool)} // check, only ObjectKinds.
func NewUnstructuredObjectTyper(groupResources []*APIGroupResources, typers ...runtime.ObjectTyper) *UnstructuredObjectTyper {
dot := &UnstructuredObjectTyper{
registered: make(map[schema.GroupVersionKind]bool),
typers: typers,
}
for _, group := range groupResources { for _, group := range groupResources {
for _, discoveryVersion := range group.Group.Versions { for _, discoveryVersion := range group.Group.Versions {
resources, ok := group.VersionedResources[discoveryVersion.Version] resources, ok := group.VersionedResources[discoveryVersion.Version]
@ -55,17 +61,29 @@ func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *Unstructur
// because runtime.Unstructured object should always have group,version,kind // because runtime.Unstructured object should always have group,version,kind
// information set. // information set.
func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) { func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) {
if _, ok := obj.(runtime.Unstructured); !ok { if _, ok := obj.(runtime.Unstructured); ok {
return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", 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{gvk}, false, nil
} }
gvk := obj.GetObjectKind().GroupVersionKind() var lastErr error
if len(gvk.Kind) == 0 { for _, typer := range d.typers {
return nil, false, runtime.NewMissingKindErr("unstructured object has no kind") gvks, unversioned, err := typer.ObjectKinds(obj)
if err != nil {
lastErr = err
continue
}
return gvks, unversioned, nil
} }
if len(gvk.Version) == 0 { if lastErr == nil {
return nil, false, runtime.NewMissingVersionErr("unstructured object has no version") lastErr = runtime.NewNotRegisteredErrForType(reflect.TypeOf(obj))
} }
return []schema.GroupVersionKind{gvk}, false, nil return nil, false, lastErr
} }
// Recognizes returns true if the provided group,version,kind was in the // Recognizes returns true if the provided group,version,kind was in the

View File

@ -84,7 +84,7 @@ func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, e
// information. // information.
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
if _, ok := obj.(*unstructured.Unstructured); !ok { if _, ok := obj.(*unstructured.Unstructured); !ok {
return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) return nil, false, fmt.Errorf("type %T is invalid for determining dynamic object types", obj)
} }
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
} }