mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
describe: use unstructured objects
This commit is contained in:
parent
b6d4f371cd
commit
06c12f6716
@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -111,8 +112,11 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
|||||||
return cmdutil.UsageError(cmd, "Required resource not specified.")
|
return cmdutil.UsageError(cmd, "Required resource not specified.")
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper, typer := f.Object()
|
mapper, typer, err := f.UnstructuredObject()
|
||||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||||
FilenameParam(enforceNamespace, options).
|
FilenameParam(enforceNamespace, options).
|
||||||
@ -168,7 +172,11 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *kubectl.DescriberSettings, out io.Writer, originalError error) error {
|
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *kubectl.DescriberSettings, out io.Writer, originalError error) error {
|
||||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
mapper, typer, err := f.UnstructuredObject()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
|
||||||
NamespaceParam(namespace).DefaultNamespace().
|
NamespaceParam(namespace).DefaultNamespace().
|
||||||
ResourceTypeOrNameArgs(true, rsrc).
|
ResourceTypeOrNameArgs(true, rsrc).
|
||||||
SingleResourceType().
|
SingleResourceType().
|
||||||
|
@ -30,11 +30,11 @@ import (
|
|||||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||||
func TestDescribeUnknownSchemaObject(t *testing.T) {
|
func TestDescribeUnknownSchemaObject(t *testing.T) {
|
||||||
d := &testDescriber{Output: "test output"}
|
d := &testDescriber{Output: "test output"}
|
||||||
f, tf, codec, ns := cmdtesting.NewTestFactory()
|
f, tf, codec, _ := cmdtesting.NewTestFactory()
|
||||||
tf.Describer = d
|
tf.Describer = d
|
||||||
tf.Client = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
|
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
|
||||||
}
|
}
|
||||||
tf.Namespace = "non-default"
|
tf.Namespace = "non-default"
|
||||||
@ -43,6 +43,31 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
|
|||||||
cmd := NewCmdDescribe(f, buf, buferr)
|
cmd := NewCmdDescribe(f, buf, buferr)
|
||||||
cmd.Run(cmd, []string{"type", "foo"})
|
cmd.Run(cmd, []string{"type", "foo"})
|
||||||
|
|
||||||
|
if d.Name != "foo" || d.Namespace != "" {
|
||||||
|
t.Errorf("unexpected describer: %#v", d)
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf.String() != fmt.Sprintf("%s", d.Output) {
|
||||||
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||||
|
func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) {
|
||||||
|
d := &testDescriber{Output: "test output"}
|
||||||
|
f, tf, codec, _ := cmdtesting.NewTestFactory()
|
||||||
|
tf.Describer = d
|
||||||
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
|
APIRegistry: api.Registry,
|
||||||
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
|
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))},
|
||||||
|
}
|
||||||
|
tf.Namespace = "non-default"
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
buferr := bytes.NewBuffer([]byte{})
|
||||||
|
cmd := NewCmdDescribe(f, buf, buferr)
|
||||||
|
cmd.Run(cmd, []string{"namespacedtype", "foo"})
|
||||||
|
|
||||||
if d.Name != "foo" || d.Namespace != "non-default" {
|
if d.Name != "foo" || d.Namespace != "non-default" {
|
||||||
t.Errorf("unexpected describer: %#v", d)
|
t.Errorf("unexpected describer: %#v", d)
|
||||||
}
|
}
|
||||||
@ -54,12 +79,12 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
|
|||||||
|
|
||||||
func TestDescribeObject(t *testing.T) {
|
func TestDescribeObject(t *testing.T) {
|
||||||
_, _, rc := testData()
|
_, _, rc := testData()
|
||||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
d := &testDescriber{Output: "test output"}
|
d := &testDescriber{Output: "test output"}
|
||||||
tf.Describer = d
|
tf.Describer = d
|
||||||
tf.Client = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
switch p, m := req.URL.Path, req.Method; {
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "GET":
|
case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "GET":
|
||||||
@ -88,12 +113,12 @@ func TestDescribeObject(t *testing.T) {
|
|||||||
|
|
||||||
func TestDescribeListObjects(t *testing.T) {
|
func TestDescribeListObjects(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
d := &testDescriber{Output: "test output"}
|
d := &testDescriber{Output: "test output"}
|
||||||
tf.Describer = d
|
tf.Describer = d
|
||||||
tf.Client = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,12 +134,12 @@ func TestDescribeListObjects(t *testing.T) {
|
|||||||
|
|
||||||
func TestDescribeObjectShowEvents(t *testing.T) {
|
func TestDescribeObjectShowEvents(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
d := &testDescriber{Output: "test output"}
|
d := &testDescriber{Output: "test output"}
|
||||||
tf.Describer = d
|
tf.Describer = d
|
||||||
tf.Client = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,12 +156,12 @@ func TestDescribeObjectShowEvents(t *testing.T) {
|
|||||||
|
|
||||||
func TestDescribeObjectSkipEvents(t *testing.T) {
|
func TestDescribeObjectSkipEvents(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||||
d := &testDescriber{Output: "test output"}
|
d := &testDescriber{Output: "test output"}
|
||||||
tf.Describer = d
|
tf.Describer = d
|
||||||
tf.Client = &fake.RESTClient{
|
tf.UnstructuredClient = &fake.RESTClient{
|
||||||
APIRegistry: api.Registry,
|
APIRegistry: api.Registry,
|
||||||
NegotiatedSerializer: ns,
|
NegotiatedSerializer: unstructuredSerializer,
|
||||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,60 @@ func NewInternalType(kind, apiversion, name string) *InternalType {
|
|||||||
return &item
|
return &item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InternalNamespacedType struct {
|
||||||
|
Kind string
|
||||||
|
APIVersion string
|
||||||
|
|
||||||
|
Name string
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalNamespacedType struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
APIVersion string `json:"apiVersion"`
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalNamespacedType2 struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
APIVersion string `json:"apiVersion"`
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj *InternalNamespacedType) GetObjectKind() schema.ObjectKind { return obj }
|
||||||
|
func (obj *InternalNamespacedType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
||||||
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||||
|
}
|
||||||
|
func (obj *InternalNamespacedType) GroupVersionKind() schema.GroupVersionKind {
|
||||||
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||||
|
}
|
||||||
|
func (obj *ExternalNamespacedType) GetObjectKind() schema.ObjectKind { return obj }
|
||||||
|
func (obj *ExternalNamespacedType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
||||||
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||||
|
}
|
||||||
|
func (obj *ExternalNamespacedType) GroupVersionKind() schema.GroupVersionKind {
|
||||||
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||||
|
}
|
||||||
|
func (obj *ExternalNamespacedType2) GetObjectKind() schema.ObjectKind { return obj }
|
||||||
|
func (obj *ExternalNamespacedType2) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
||||||
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||||
|
}
|
||||||
|
func (obj *ExternalNamespacedType2) GroupVersionKind() schema.GroupVersionKind {
|
||||||
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInternalNamespacedType(kind, apiversion, name, namespace string) *InternalNamespacedType {
|
||||||
|
item := InternalNamespacedType{Kind: kind,
|
||||||
|
APIVersion: apiversion,
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace}
|
||||||
|
return &item
|
||||||
|
}
|
||||||
|
|
||||||
var versionErr = errors.New("not a version")
|
var versionErr = errors.New("not a version")
|
||||||
|
|
||||||
func versionErrIfFalse(b bool) error {
|
func versionErrIfFalse(b bool) error {
|
||||||
@ -109,11 +163,17 @@ var ValidVersionGV = schema.GroupVersion{Group: "apitest", Version: ValidVersion
|
|||||||
|
|
||||||
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
|
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
|
||||||
scheme := runtime.NewScheme()
|
scheme := runtime.NewScheme()
|
||||||
|
|
||||||
scheme.AddKnownTypeWithName(InternalGV.WithKind("Type"), &InternalType{})
|
scheme.AddKnownTypeWithName(InternalGV.WithKind("Type"), &InternalType{})
|
||||||
scheme.AddKnownTypeWithName(UnlikelyGV.WithKind("Type"), &ExternalType{})
|
scheme.AddKnownTypeWithName(UnlikelyGV.WithKind("Type"), &ExternalType{})
|
||||||
//This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
//This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
||||||
scheme.AddKnownTypeWithName(ValidVersionGV.WithKind("Type"), &ExternalType2{})
|
scheme.AddKnownTypeWithName(ValidVersionGV.WithKind("Type"), &ExternalType2{})
|
||||||
|
|
||||||
|
scheme.AddKnownTypeWithName(InternalGV.WithKind("NamespacedType"), &InternalNamespacedType{})
|
||||||
|
scheme.AddKnownTypeWithName(UnlikelyGV.WithKind("NamespacedType"), &ExternalNamespacedType{})
|
||||||
|
//This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
||||||
|
scheme.AddKnownTypeWithName(ValidVersionGV.WithKind("NamespacedType"), &ExternalNamespacedType2{})
|
||||||
|
|
||||||
codecs := serializer.NewCodecFactory(scheme)
|
codecs := serializer.NewCodecFactory(scheme)
|
||||||
codec := codecs.LegacyCodec(UnlikelyGV)
|
codec := codecs.LegacyCodec(UnlikelyGV)
|
||||||
mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{UnlikelyGV, ValidVersionGV}, func(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
|
mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{UnlikelyGV, ValidVersionGV}, func(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||||
@ -603,6 +663,7 @@ func testDynamicResources() []*discovery.APIGroupResources {
|
|||||||
{Name: "componentstatuses", Namespaced: false, Kind: "ComponentStatus"},
|
{Name: "componentstatuses", Namespaced: false, Kind: "ComponentStatus"},
|
||||||
{Name: "nodes", Namespaced: false, Kind: "Node"},
|
{Name: "nodes", Namespaced: false, Kind: "Node"},
|
||||||
{Name: "type", Namespaced: false, Kind: "Type"},
|
{Name: "type", Namespaced: false, Kind: "Type"},
|
||||||
|
{Name: "namespacedtype", Namespaced: true, Kind: "NamespacedType"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user