mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
make kubectl get generic with respect to objects
This commit is contained in:
parent
7fe9bd4c30
commit
61673c4b39
@ -26,6 +26,14 @@ import (
|
||||
|
||||
// IsListType returns true if the provided Object has a slice called Items
|
||||
func IsListType(obj runtime.Object) bool {
|
||||
// if we're a runtime.Unstructured, check to see if we have an `items` key
|
||||
// This is a list type for recognition, but other Items type methods will fail on it
|
||||
// and give you errors.
|
||||
if unstructured, ok := obj.(*runtime.Unstructured); ok {
|
||||
_, ok := unstructured.Object["items"]
|
||||
return ok
|
||||
}
|
||||
|
||||
_, err := GetItemsPtr(obj)
|
||||
return err == nil
|
||||
}
|
||||
@ -39,6 +47,7 @@ func GetItemsPtr(list runtime.Object) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := v.FieldByName("Items")
|
||||
if !items.IsValid() {
|
||||
return nil, fmt.Errorf("no Items field in %#v", list)
|
||||
@ -117,6 +126,13 @@ func SetList(list runtime.Object, objects []runtime.Object) error {
|
||||
slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
|
||||
for i := range objects {
|
||||
dest := slice.Index(i)
|
||||
|
||||
// check to see if you're directly assignable
|
||||
if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
|
||||
dest.Set(reflect.ValueOf(objects[i]))
|
||||
continue
|
||||
}
|
||||
|
||||
src, err := conversion.EnforcePtr(objects[i])
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -229,6 +229,27 @@ func TestSetListToRuntimeObjectArray(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetListToMatchingType(t *testing.T) {
|
||||
pl := &runtime.UnstructuredList{}
|
||||
list := []runtime.Object{
|
||||
&runtime.Unstructured{Object: map[string]interface{}{"foo": 1}},
|
||||
&runtime.Unstructured{Object: map[string]interface{}{"foo": 2}},
|
||||
&runtime.Unstructured{Object: map[string]interface{}{"foo": 3}},
|
||||
}
|
||||
err := meta.SetList(pl, list)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if e, a := len(list), len(pl.Items); e != a {
|
||||
t.Fatalf("Expected %v, got %v", e, a)
|
||||
}
|
||||
for i := range list {
|
||||
if e, a := list[i], pl.Items[i]; e != a {
|
||||
t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetExtractListRoundTrip(t *testing.T) {
|
||||
fuzzer := fuzz.New().NilChance(0).NumElements(1, 5)
|
||||
for i := 0; i < 5; i++ {
|
||||
|
@ -182,11 +182,9 @@ go_test(
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/runtime/serializer:go_default_library",
|
||||
"//pkg/runtime/serializer/json:go_default_library",
|
||||
"//pkg/runtime/serializer/streaming:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/diff:go_default_library",
|
||||
"//pkg/util/intstr:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//pkg/util/term:go_default_library",
|
||||
|
@ -28,16 +28,12 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
var unstructuredSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{
|
||||
MediaType: "application/json",
|
||||
EncodesAsText: true,
|
||||
Serializer: runtime.UnstructuredJSONScheme})
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
|
||||
func TestDeleteObjectByTuple(t *testing.T) {
|
||||
_, _, rc := testData()
|
||||
|
@ -149,7 +149,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
|
||||
showKind := cmdutil.GetFlagBool(cmd, "show-kind")
|
||||
mapper, typer := f.Object()
|
||||
mapper, typer, err := f.UnstructuredObject()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printAll := false
|
||||
filterFuncs := f.DefaultResourceFilterFunc()
|
||||
filterOpts := f.DefaultResourceFilterOptions(cmd, allNamespaces)
|
||||
@ -196,7 +199,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
// handle watch separately since we cannot watch multiple resource types
|
||||
isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
|
||||
if isWatch || isWatchOnly {
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
SelectorParam(selector).
|
||||
@ -281,7 +284,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
return nil
|
||||
}
|
||||
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
SelectorParam(selector).
|
||||
@ -302,18 +305,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
}
|
||||
|
||||
if generic {
|
||||
clientConfig, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// the outermost object will be converted to the output-version, but inner
|
||||
// objects can use their mappings
|
||||
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
|
||||
// 1. if there is more than one item, combine them all into a single list
|
||||
// 2. if there is a single item and that item is a list, leave it as its specific list
|
||||
// 3. if there is a single item and it is not a a list, leave it as a single item
|
||||
var errs []error
|
||||
singular := false
|
||||
infos, err := r.IntoSingular(&singular).Infos()
|
||||
@ -332,9 +327,22 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
res = infos[0].ResourceMapping().Resource
|
||||
}
|
||||
|
||||
obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder())
|
||||
if err != nil {
|
||||
return err
|
||||
var obj runtime.Object
|
||||
if singular {
|
||||
obj = infos[0].Object
|
||||
} else {
|
||||
// we have more than one item, so coerce all items into a list
|
||||
list := &runtime.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
for _, info := range infos {
|
||||
list.Items = append(list.Items, info.Object.(*runtime.Unstructured))
|
||||
}
|
||||
obj = list
|
||||
}
|
||||
|
||||
isList := meta.IsListType(obj)
|
||||
@ -343,11 +351,24 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filteredObj, err := cmdutil.ObjectListToVersionedObject(items, version)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
// take the filtered items and create a new list for display
|
||||
list := &runtime.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
if err := printer.PrintObj(filteredObj, out); err != nil {
|
||||
if listMeta, err := meta.ListAccessor(obj); err == nil {
|
||||
list.Object["selfLink"] = listMeta.GetSelfLink()
|
||||
list.Object["resourceVersion"] = listMeta.GetResourceVersion()
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
list.Items = append(list.Items, item.(*runtime.Unstructured))
|
||||
}
|
||||
if err := printer.PrintObj(list, out); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
@ -390,24 +411,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
}
|
||||
var sorter *kubectl.RuntimeSort
|
||||
if len(sorting) > 0 && len(objs) > 1 {
|
||||
clientConfig, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for ix := range infos {
|
||||
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: questionable
|
||||
if sorter, err = kubectl.SortObjects(f.Decoder(true), objs, sorting); err != nil {
|
||||
return err
|
||||
|
@ -19,7 +19,6 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
encjson "encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -37,10 +36,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer/json"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/kubernetes/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
"k8s.io/kubernetes/pkg/watch/versioned"
|
||||
)
|
||||
@ -120,10 +117,11 @@ func testComponentStatusData() *api.ComponentStatusList {
|
||||
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
f, tf, codec, ns := cmdtesting.NewTestFactory()
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
_, _, codec, _ := cmdtesting.NewTestFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -135,114 +133,39 @@ func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Run(cmd, []string{"type", "foo"})
|
||||
|
||||
expected := cmdtesting.NewInternalType("", "", "foo")
|
||||
actual := tf.Printer.(*testPrinter).Objects[0]
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
expected := []runtime.Object{cmdtesting.NewInternalType("", "", "foo")}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatal(actual)
|
||||
}
|
||||
if buf.String() != fmt.Sprintf("%#v", expected) {
|
||||
t.Errorf("unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
// Because api.List is part of the Kube API, resource.Builder has to perform a conversion on
|
||||
// api.Scheme, which may not have access to all objects, and not all objects are at the same
|
||||
// internal versioning scheme. This test verifies that two isolated schemes (Test, and api.Scheme)
|
||||
// can be conjoined into a single output object.
|
||||
//
|
||||
// The expected behavior of the `kubectl get` command is:
|
||||
// 1. objects using unrecognized schemes will always be returned using that scheme/version, "unlikelyversion" in this test;
|
||||
// 2. if the specified output-version is a recognized, valid Scheme, then the list should use that scheme, and otherwise it will default to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test;
|
||||
// 3a. if the specified output-version is a recognized, valid Scheme, in which the requested object (replicationcontroller) can be represented, then the object should be returned using that version;
|
||||
// 3b. otherwise if the specified output-version is unrecognized, but the requested object (replicationcontroller) is recognized by the client's codec, then it will be converted to the client version, registered.GroupOrDie(api.GroupName).GroupVersion.String() in this test.
|
||||
func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
outputVersion string
|
||||
listVersion string
|
||||
testtypeVersion string
|
||||
rcVersion string
|
||||
}{
|
||||
"handles specific version": {
|
||||
outputVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
listVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
testtypeVersion: cmdtesting.UnlikelyGV.String(),
|
||||
rcVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
},
|
||||
"handles second specific version": {
|
||||
outputVersion: "unlikely.group/unlikelyversion",
|
||||
listVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
testtypeVersion: cmdtesting.UnlikelyGV.String(),
|
||||
rcVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(), // see expected behavior 3b
|
||||
},
|
||||
"handles common version": {
|
||||
outputVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
listVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
testtypeVersion: cmdtesting.UnlikelyGV.String(),
|
||||
rcVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String(),
|
||||
},
|
||||
}
|
||||
for k, test := range testCases {
|
||||
apiCodec := testapi.Default.Codec()
|
||||
apiNegotiatedSerializer := testapi.Default.NegotiatedSerializer()
|
||||
regularClient := &fake.RESTClient{
|
||||
NegotiatedSerializer: apiNegotiatedSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(apiCodec, &api.ReplicationController{ObjectMeta: api.ObjectMeta{Name: "foo"}})}, nil
|
||||
}),
|
||||
for i, obj := range actual {
|
||||
expectedJSON := runtime.EncodeOrDie(codec, expected[i])
|
||||
expectedMap := map[string]interface{}{}
|
||||
if err := encjson.Unmarshal([]byte(expectedJSON), &expectedMap); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, tf, codec := cmdtesting.NewMixedFactory(regularClient)
|
||||
negotiatedSerializer := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: negotiatedSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))}, nil
|
||||
}),
|
||||
actualJSON := runtime.EncodeOrDie(api.Codecs.LegacyCodec(), obj)
|
||||
actualMap := map[string]interface{}{}
|
||||
if err := encjson.Unmarshal([]byte(actualJSON), &actualMap); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdGet(f, buf, errBuf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("output", "json")
|
||||
|
||||
cmd.Flags().Set("output-version", test.outputVersion)
|
||||
err := RunGet(f, buf, errBuf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
out := make(map[string]interface{})
|
||||
if err := encjson.Unmarshal(buf.Bytes(), &out); err != nil {
|
||||
t.Errorf("%s: unexpected error: %v\n%s", k, err, buf.String())
|
||||
continue
|
||||
}
|
||||
if out["apiVersion"] != test.listVersion {
|
||||
t.Errorf("%s: unexpected list: %#v", k, out)
|
||||
}
|
||||
arr := out["items"].([]interface{})
|
||||
if arr[0].(map[string]interface{})["apiVersion"] != test.testtypeVersion {
|
||||
t.Errorf("%s: unexpected list: %#v", k, out)
|
||||
}
|
||||
if arr[1].(map[string]interface{})["apiVersion"] != test.rcVersion {
|
||||
t.Errorf("%s: unexpected list: %#v", k, out)
|
||||
if !reflect.DeepEqual(expectedMap, actualMap) {
|
||||
t.Errorf("unexpected object: \n%#v\n%#v", expectedMap, actualMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
|
||||
func TestGetSchemaObject(t *testing.T) {
|
||||
f, tf, _, _ := cmdtesting.NewTestFactory()
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Mapper = testapi.Default.RESTMapper()
|
||||
tf.Typer = api.Scheme
|
||||
codec := testapi.Default.Codec()
|
||||
ns := testapi.Default.NegotiatedSerializer()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationController{ObjectMeta: api.ObjectMeta{Name: "foo"}})},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -261,10 +184,10 @@ func TestGetSchemaObject(t *testing.T) {
|
||||
func TestGetObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -276,10 +199,8 @@ func TestGetObjects(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
expected := []runtime.Object{&pods.Items[0]}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -306,10 +227,10 @@ func TestGetSortedObjects(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -327,23 +248,37 @@ func TestGetSortedObjects(t *testing.T) {
|
||||
|
||||
// expect sorted: a,b,c
|
||||
expected := []runtime.Object{&pods.Items[2], &pods.Items[1], &pods.Items[0]}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
}
|
||||
|
||||
func verifyObjects(t *testing.T, expected, actual []runtime.Object) {
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatal(actual)
|
||||
}
|
||||
for i, obj := range actual {
|
||||
actualObj, err := runtime.Decode(
|
||||
api.Codecs.UniversalDecoder(),
|
||||
[]byte(runtime.EncodeOrDie(api.Codecs.LegacyCodec(), obj)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !api.Semantic.DeepEqual(expected[i], actualObj) {
|
||||
t.Errorf("unexpected object: \n%#v\n%#v", expected[i], actualObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetObjectsIdentifiedByFile(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -356,10 +291,8 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) {
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
expected := []runtime.Object{&pods.Items[0]}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -368,10 +301,10 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) {
|
||||
func TestGetListObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -384,12 +317,10 @@ func TestGetListObjects(t *testing.T) {
|
||||
|
||||
expected, err := extractResourceList([]runtime.Object{pods})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: expected %#v, got %#v", expected, actual)
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -412,10 +343,10 @@ func extractResourceList(objs []runtime.Object) ([]runtime.Object, error) {
|
||||
func TestGetAllListObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -429,12 +360,10 @@ func TestGetAllListObjects(t *testing.T) {
|
||||
|
||||
expected, err := extractResourceList([]runtime.Object{pods})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v %#v", expected, actual)
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -443,10 +372,10 @@ func TestGetAllListObjects(t *testing.T) {
|
||||
func TestGetListComponentStatus(t *testing.T) {
|
||||
statuses := testComponentStatusData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, statuses)},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -459,12 +388,10 @@ func TestGetListComponentStatus(t *testing.T) {
|
||||
|
||||
expected, err := extractResourceList([]runtime.Object{statuses})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: expected %#v, got %#v", expected, actual)
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -473,10 +400,10 @@ func TestGetListComponentStatus(t *testing.T) {
|
||||
func TestGetMultipleTypeObjects(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/pods":
|
||||
@ -499,12 +426,10 @@ func TestGetMultipleTypeObjects(t *testing.T) {
|
||||
|
||||
expected, err := extractResourceList([]runtime.Object{pods, svc})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -513,10 +438,10 @@ func TestGetMultipleTypeObjects(t *testing.T) {
|
||||
func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/pods":
|
||||
@ -574,10 +499,10 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Query().Get(unversioned.LabelSelectorQueryParam(registered.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
@ -605,12 +530,10 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
|
||||
|
||||
expected, err := extractResourceList([]runtime.Object{pods, svc})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -627,10 +550,10 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/nodes/foo":
|
||||
@ -653,10 +576,8 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"services/bar", "node/foo"})
|
||||
|
||||
expected := []runtime.Object{&svc.Items[0], node}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !api.Semantic.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %s", diff.ObjectDiff(expected, actual))
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -665,10 +586,10 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
|
||||
func TestGetByNameForcesFlag(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
@ -758,7 +679,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
||||
func TestWatchSelector(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
podList := &api.PodList{
|
||||
Items: pods,
|
||||
@ -767,7 +688,7 @@ func TestWatchSelector(t *testing.T) {
|
||||
},
|
||||
}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Query().Get(unversioned.LabelSelectorQueryParam(registered.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
@ -795,10 +716,8 @@ func TestWatchSelector(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
|
||||
expected := []runtime.Object{podList, events[2].Object, events[3].Object}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object:\nExpected: %#v\n\nGot: %#v\n\n", expected, actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -807,10 +726,10 @@ func TestWatchSelector(t *testing.T) {
|
||||
func TestWatchResource(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/pods/foo":
|
||||
@ -834,10 +753,8 @@ func TestWatchResource(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
expected := []runtime.Object{&pods[1], events[2].Object, events[3].Object}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object:\nExpected: %#v\n\nGot: %#v\n\n", expected, actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -846,10 +763,10 @@ func TestWatchResource(t *testing.T) {
|
||||
func TestWatchResourceIdentifiedByFile(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/replicationcontrollers/cassandra":
|
||||
@ -874,10 +791,7 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) {
|
||||
cmd.Run(cmd, []string{})
|
||||
|
||||
expected := []runtime.Object{&pods[1], events[2].Object, events[3].Object}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected object: %#v unexpected object: %#v", expected, actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
@ -887,10 +801,10 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) {
|
||||
func TestWatchOnlyResource(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/pods/foo":
|
||||
@ -914,10 +828,8 @@ func TestWatchOnlyResource(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
expected := []runtime.Object{events[2].Object, events[3].Object}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
@ -926,7 +838,7 @@ func TestWatchOnlyResource(t *testing.T) {
|
||||
func TestWatchOnlyList(t *testing.T) {
|
||||
pods, events := watchTestData()
|
||||
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
podList := &api.PodList{
|
||||
Items: pods,
|
||||
@ -935,7 +847,7 @@ func TestWatchOnlyList(t *testing.T) {
|
||||
},
|
||||
}
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch req.URL.Path {
|
||||
case "/namespaces/test/pods":
|
||||
@ -959,10 +871,8 @@ func TestWatchOnlyList(t *testing.T) {
|
||||
cmd.Run(cmd, []string{"pods"})
|
||||
|
||||
expected := []runtime.Object{events[2].Object, events[3].Object}
|
||||
actual := tf.Printer.(*testPrinter).Objects
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("unexpected object: %#v", actual)
|
||||
}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
|
@ -182,7 +182,11 @@ func (f *FakeFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
}
|
||||
|
||||
func (f *FakeFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
return nil, nil, nil
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructured)
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
|
||||
return cmdutil.NewShortcutExpander(mapper, nil), typer, nil
|
||||
}
|
||||
|
||||
func (f *FakeFactory) Decoder(bool) runtime.Decoder {
|
||||
@ -379,7 +383,7 @@ func (f *fakeMixedFactory) ClientForMapping(m *meta.RESTMapping) (resource.RESTC
|
||||
}
|
||||
|
||||
func NewMixedFactory(apiClient resource.RESTClient) (cmdutil.Factory, *TestFactory, runtime.Codec) {
|
||||
f, t, c, _ := NewTestFactory()
|
||||
f, t, c, _ := NewAPIFactory()
|
||||
return &fakeMixedFactory{
|
||||
Factory: f,
|
||||
tf: t,
|
||||
@ -545,6 +549,9 @@ func testDynamicResources() []*discovery.APIGroupResources {
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
{Name: "services", Namespaced: true, Kind: "Service"},
|
||||
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController"},
|
||||
{Name: "componentstatuses", Namespaced: false, Kind: "ComponentStatus"},
|
||||
{Name: "nodes", Namespaced: false, Kind: "Node"},
|
||||
{Name: "type", Namespaced: false, Kind: "Type"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -29,12 +29,10 @@ go_library(
|
||||
"//pkg/api/service:go_default_library",
|
||||
"//pkg/api/unversioned:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/apimachinery:go_default_library",
|
||||
"//pkg/apimachinery/registered:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
|
@ -33,23 +33,19 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/kubernetes/federation/apis/federation"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/service"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apimachinery"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
@ -339,21 +335,10 @@ func (f *factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
mapper := registered.RESTMapper()
|
||||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
|
||||
if err == nil {
|
||||
// register third party resources with the api machinery groups. This probably should be done, but
|
||||
// its consistent with old code, so we'll start with it.
|
||||
if err := registerThirdPartyResources(discoveryClient); err != nil {
|
||||
glog.V(1).Infof("Unable to register third party resources: %v", err)
|
||||
}
|
||||
// ThirdPartyResourceData is special. It's not discoverable, but needed for thirdparty resource listing
|
||||
// TODO eliminate this once we're truly generic.
|
||||
thirdPartyResourceDataMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{extensionsv1beta1.SchemeGroupVersion}, registered.InterfacesFor)
|
||||
thirdPartyResourceDataMapper.Add(extensionsv1beta1.SchemeGroupVersion.WithKind("ThirdPartyResourceData"), meta.RESTScopeNamespace)
|
||||
|
||||
mapper = meta.FirstHitRESTMapper{
|
||||
MultiRESTMapper: meta.MultiRESTMapper{
|
||||
discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, registered.InterfacesFor),
|
||||
thirdPartyResourceDataMapper, // needed for TPR printing
|
||||
registered.RESTMapper(), // hardcoded fall back
|
||||
registered.RESTMapper(), // hardcoded fall back
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1331,54 +1316,3 @@ func (f *factory) SuggestedPodTemplateResources() []unversioned.GroupResource {
|
||||
{Resource: "replicaset"},
|
||||
}
|
||||
}
|
||||
|
||||
// registerThirdPartyResources inspects the discovery endpoint to find thirdpartyresources in the discovery doc
|
||||
// and then registers them with the apimachinery code. I think this is done so that scheme/codec stuff works,
|
||||
// but I really don't know. Feels like this code should go away once kubectl is completely generic for generic
|
||||
// CRUD
|
||||
func registerThirdPartyResources(discoveryClient discovery.DiscoveryInterface) error {
|
||||
var versions []unversioned.GroupVersion
|
||||
var gvks []unversioned.GroupVersionKind
|
||||
var err error
|
||||
retries := 3
|
||||
for i := 0; i < retries; i++ {
|
||||
versions, gvks, err = GetThirdPartyGroupVersions(discoveryClient)
|
||||
// Retry if we got a NotFound error, because user may delete
|
||||
// a thirdparty group when the GetThirdPartyGroupVersions is
|
||||
// running.
|
||||
if err == nil || !apierrors.IsNotFound(err) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupsMap := map[string][]unversioned.GroupVersion{}
|
||||
for _, version := range versions {
|
||||
groupsMap[version.Group] = append(groupsMap[version.Group], version)
|
||||
}
|
||||
for group, versionList := range groupsMap {
|
||||
preferredExternalVersion := versionList[0]
|
||||
|
||||
thirdPartyMapper, err := kubectl.NewThirdPartyResourceMapper(versionList, getGroupVersionKinds(gvks, group))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessor := meta.NewAccessor()
|
||||
groupMeta := apimachinery.GroupMeta{
|
||||
GroupVersion: preferredExternalVersion,
|
||||
GroupVersions: versionList,
|
||||
RESTMapper: thirdPartyMapper,
|
||||
SelfLinker: runtime.SelfLinker(accessor),
|
||||
InterfacesFor: makeInterfacesFor(versionList),
|
||||
}
|
||||
if err := registered.RegisterGroup(groupMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
registered.AddThirdPartyAPIGroupVersions(versionList...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
@ -551,49 +550,6 @@ func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
|
||||
return GetRecordFlag(cmd) || (ContainsChangeCause(info) && !cmd.Flags().Changed("record"))
|
||||
}
|
||||
|
||||
// GetThirdPartyGroupVersions returns the thirdparty "group/versions"s and
|
||||
// resources supported by the server. A user may delete a thirdparty resource
|
||||
// when this function is running, so this function may return a "NotFound" error
|
||||
// due to the race.
|
||||
func GetThirdPartyGroupVersions(discovery discovery.DiscoveryInterface) ([]unversioned.GroupVersion, []unversioned.GroupVersionKind, error) {
|
||||
result := []unversioned.GroupVersion{}
|
||||
gvks := []unversioned.GroupVersionKind{}
|
||||
|
||||
groupList, err := discovery.ServerGroups()
|
||||
if err != nil {
|
||||
// On forbidden or not found, just return empty lists.
|
||||
if kerrors.IsForbidden(err) || kerrors.IsNotFound(err) {
|
||||
return result, gvks, nil
|
||||
}
|
||||
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for ix := range groupList.Groups {
|
||||
group := &groupList.Groups[ix]
|
||||
for jx := range group.Versions {
|
||||
gv, err2 := unversioned.ParseGroupVersion(group.Versions[jx].GroupVersion)
|
||||
if err2 != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Skip GroupVersionKinds that have been statically registered.
|
||||
if registered.IsRegisteredVersion(gv) {
|
||||
continue
|
||||
}
|
||||
result = append(result, gv)
|
||||
|
||||
resourceList, err := discovery.ServerResourcesForGroupVersion(group.Versions[jx].GroupVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for kx := range resourceList.APIResources {
|
||||
gvks = append(gvks, gv.WithKind(resourceList.APIResources[kx].Kind))
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, gvks, nil
|
||||
}
|
||||
|
||||
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
||||
cmd.Flags().MarkDeprecated("include-extended-apis", "No longer required.")
|
||||
|
@ -206,9 +206,18 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ix := range parsers {
|
||||
parser := parsers[ix]
|
||||
values, err := parser.FindResults(reflect.ValueOf(obj).Elem().Interface())
|
||||
|
||||
var values [][]reflect.Value
|
||||
var err error
|
||||
if unstructured, ok := obj.(*runtime.Unstructured); ok {
|
||||
values, err = parser.FindResults(unstructured.Object)
|
||||
} else {
|
||||
values, err = parser.FindResults(reflect.ValueOf(obj).Elem().Interface())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -48,28 +48,6 @@ func makeImageList(spec *api.PodSpec) string {
|
||||
return strings.Join(listOfImages(spec), ",")
|
||||
}
|
||||
|
||||
func NewThirdPartyResourceMapper(gvs []unversioned.GroupVersion, gvks []unversioned.GroupVersionKind) (meta.RESTMapper, error) {
|
||||
mapper := meta.NewDefaultRESTMapper(gvs, func(gv unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
for ix := range gvs {
|
||||
if gvs[ix].Group == gv.Group && gvs[ix].Version == gv.Version {
|
||||
return &meta.VersionInterfaces{
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: meta.NewAccessor(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
groupVersions := make([]string, 0, len(gvs))
|
||||
for ix := range gvs {
|
||||
groupVersions = append(groupVersions, gvs[ix].String())
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", gv.String(), strings.Join(groupVersions, ", "))
|
||||
})
|
||||
for ix := range gvks {
|
||||
mapper.Add(gvks[ix], meta.RESTScopeNamespace)
|
||||
}
|
||||
return mapper, nil
|
||||
}
|
||||
|
||||
// OutputVersionMapper is a RESTMapper that will prefer mappings that
|
||||
// correspond to a preferred output version (if feasible)
|
||||
type OutputVersionMapper struct {
|
||||
|
@ -241,8 +241,6 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: this is wrong, runtime.Unknown and runtime.Unstructured are not handled properly here.
|
||||
|
||||
name := "<unknown>"
|
||||
if acc, err := meta.Accessor(obj); err == nil {
|
||||
if n := acc.GetName(); len(n) > 0 {
|
||||
@ -250,12 +248,22 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
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(gvks[0])
|
||||
fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
|
||||
if kind := obj.GetObjectKind().GroupVersionKind(); len(kind.Kind) == 0 {
|
||||
// this is the old code. It's unnecessary on decoded external objects, but on internal objects
|
||||
// you may have to do it. Tests are definitely calling it with internals and I'm not sure who else
|
||||
// is
|
||||
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(gvks[0])
|
||||
fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
|
||||
} else {
|
||||
fmt.Fprintf(w, "<unknown>/%s\n", name)
|
||||
}
|
||||
|
||||
} else {
|
||||
fmt.Fprintf(w, "<unknown>/%s\n", name)
|
||||
// TODO: this is wrong, it assumes that meta knows about all Kinds - should take a RESTMapper
|
||||
_, resource := meta.KindToResource(kind)
|
||||
fmt.Fprintf(w, "%s/%s\n", resource.Resource, name)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -2251,6 +2259,18 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
|
||||
w = GetNewTabWriter(output)
|
||||
defer w.Flush()
|
||||
}
|
||||
|
||||
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand before
|
||||
// trying to print, since the printers are keyed by type. This is extremely expensive.
|
||||
switch obj.(type) {
|
||||
case *runtime.Unstructured, *runtime.Unknown:
|
||||
if objBytes, err := runtime.Encode(api.Codecs.LegacyCodec(), obj); err == nil {
|
||||
if decodedObj, err := runtime.Decode(api.Codecs.UniversalDecoder(), objBytes); err == nil {
|
||||
obj = decodedObj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(obj)
|
||||
if handler := h.handlerMap[t]; handler != nil {
|
||||
if !h.options.NoHeaders && t != h.lastType {
|
||||
@ -2271,9 +2291,78 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
|
||||
}
|
||||
return resultValue.Interface().(error)
|
||||
}
|
||||
|
||||
// we don't recognize this type, but we can still attempt to print some reasonable information about.
|
||||
unstructured, ok := obj.(*runtime.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("error: unknown type %#v", obj)
|
||||
}
|
||||
|
||||
if _, err := meta.Accessor(obj); err == nil {
|
||||
if !h.options.NoHeaders && t != h.lastType {
|
||||
headers := []string{"NAME", "KIND"}
|
||||
headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
|
||||
// LABELS is always the last column.
|
||||
headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
|
||||
if h.options.WithNamespace {
|
||||
headers = append(withNamespacePrefixColumns, headers...)
|
||||
}
|
||||
h.printHeader(headers, w)
|
||||
h.lastType = t
|
||||
}
|
||||
// if the error isn't nil, report the "I don't recognize this" error
|
||||
if err := printUnstructured(unstructured, w, h.options); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// we failed all reasonable printing efforts, report failure
|
||||
return fmt.Errorf("error: unknown type %#v", obj)
|
||||
}
|
||||
|
||||
func printUnstructured(unstructured *runtime.Unstructured, w io.Writer, options PrintOptions) error {
|
||||
metadata, err := meta.Accessor(unstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", metadata.GetNamespace()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
kind := "<missing>"
|
||||
if objKind, ok := unstructured.Object["kind"]; ok {
|
||||
if str, ok := objKind.(string); ok {
|
||||
kind = str
|
||||
}
|
||||
}
|
||||
if objAPIVersion, ok := unstructured.Object["apiVersion"]; ok {
|
||||
if str, ok := objAPIVersion.(string); ok {
|
||||
version, err := unversioned.ParseGroupVersion(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kind = kind + "." + version.Version + "." + version.Group
|
||||
}
|
||||
}
|
||||
name := formatResourceName(options.Kind, metadata.GetName(), options.WithKind)
|
||||
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s", name, kind); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, AppendLabels(metadata.GetLabels(), options.ColumnLabels)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, AppendAllLabels(options.ShowLabels, metadata.GetLabels())); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
|
||||
type TemplatePrinter struct {
|
||||
rawTemplate string
|
||||
@ -2299,10 +2388,18 @@ func (p *TemplatePrinter) AfterPrint(w io.Writer, res string) error {
|
||||
|
||||
// PrintObj formats the obj with the Go Template.
|
||||
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
data, err := json.Marshal(obj)
|
||||
var data []byte
|
||||
var err error
|
||||
if unstructured, ok := obj.(*runtime.Unstructured); ok {
|
||||
data, err = json.Marshal(unstructured.Object)
|
||||
} else {
|
||||
data, err = json.Marshal(obj)
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return err
|
||||
@ -2462,6 +2559,20 @@ func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
if unknown, ok := obj.(*runtime.Unknown); ok {
|
||||
data, err := json.Marshal(unknown)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryObj = map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &queryObj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if unstructured, ok := obj.(*runtime.Unstructured); ok {
|
||||
queryObj = unstructured.Object
|
||||
}
|
||||
|
||||
if err := j.JSONPath.Execute(w, queryObj); err != nil {
|
||||
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
|
||||
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
|
||||
|
@ -109,7 +109,13 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri
|
||||
}
|
||||
}
|
||||
|
||||
values, err := parser.FindResults(reflect.ValueOf(objs[0]).Elem().Interface())
|
||||
var values [][]reflect.Value
|
||||
if unstructured, ok := objs[0].(*runtime.Unstructured); ok {
|
||||
values, err = parser.FindResults(unstructured.Object)
|
||||
} else {
|
||||
values, err = parser.FindResults(reflect.ValueOf(objs[0]).Elem().Interface())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -182,6 +188,66 @@ func isLess(i, j reflect.Value) (bool, error) {
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
|
||||
case reflect.Interface:
|
||||
switch itype := i.Interface().(type) {
|
||||
case uint8:
|
||||
if jtype, ok := j.Interface().(uint8); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case uint16:
|
||||
if jtype, ok := j.Interface().(uint16); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case uint32:
|
||||
if jtype, ok := j.Interface().(uint32); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case uint64:
|
||||
if jtype, ok := j.Interface().(uint64); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case int8:
|
||||
if jtype, ok := j.Interface().(int8); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case int16:
|
||||
if jtype, ok := j.Interface().(int16); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case int32:
|
||||
if jtype, ok := j.Interface().(int32); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case int64:
|
||||
if jtype, ok := j.Interface().(int64); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case uint:
|
||||
if jtype, ok := j.Interface().(uint); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case int:
|
||||
if jtype, ok := j.Interface().(int); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case float32:
|
||||
if jtype, ok := j.Interface().(float32); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case float64:
|
||||
if jtype, ok := j.Interface().(float64); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
case string:
|
||||
if jtype, ok := j.Interface().(string); ok {
|
||||
return itype < jtype, nil
|
||||
}
|
||||
default:
|
||||
return false, fmt.Errorf("unsortable type: %T", itype)
|
||||
}
|
||||
return false, fmt.Errorf("unsortable interface: %v", i.Kind())
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("unsortable type: %v", i.Kind())
|
||||
}
|
||||
@ -194,11 +260,24 @@ func (r *RuntimeSort) Less(i, j int) bool {
|
||||
parser := jsonpath.New("sorting")
|
||||
parser.Parse(r.field)
|
||||
|
||||
iValues, err := parser.FindResults(reflect.ValueOf(iObj).Elem().Interface())
|
||||
var iValues [][]reflect.Value
|
||||
var jValues [][]reflect.Value
|
||||
var err error
|
||||
|
||||
if unstructured, ok := iObj.(*runtime.Unstructured); ok {
|
||||
iValues, err = parser.FindResults(unstructured.Object)
|
||||
} else {
|
||||
iValues, err = parser.FindResults(reflect.ValueOf(iObj).Elem().Interface())
|
||||
}
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to get i values for %#v using %s (%#v)", iObj, r.field, err)
|
||||
}
|
||||
jValues, err := parser.FindResults(reflect.ValueOf(jObj).Elem().Interface())
|
||||
|
||||
if unstructured, ok := jObj.(*runtime.Unstructured); ok {
|
||||
jValues, err = parser.FindResults(unstructured.Object)
|
||||
} else {
|
||||
jValues, err = parser.FindResults(reflect.ValueOf(jObj).Elem().Interface())
|
||||
}
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to get j values for %#v using %s (%v)", jObj, r.field, err)
|
||||
}
|
||||
|
@ -551,25 +551,25 @@ var _ = framework.KubeDescribe("Kubectl client", func() {
|
||||
By("checking the result")
|
||||
forEachReplicationController(c, ns, "app", "redis", validateReplicationControllerConfiguration)
|
||||
})
|
||||
It("should reuse nodePort when apply to an existing SVC", func() {
|
||||
It("should reuse port when apply to an existing SVC", func() {
|
||||
serviceJson := readTestFileOrDie(redisServiceFilename)
|
||||
nsFlag := fmt.Sprintf("--namespace=%v", ns)
|
||||
|
||||
By("creating Redis SVC")
|
||||
framework.RunKubectlOrDieInput(string(serviceJson[:]), "create", "-f", "-", nsFlag)
|
||||
|
||||
By("getting the original nodePort")
|
||||
originalNodePort := framework.RunKubectlOrDie("get", "service", "redis-master", nsFlag, "-o", "jsonpath={.spec.ports[0].nodePort}")
|
||||
By("getting the original port")
|
||||
originalNodePort := framework.RunKubectlOrDie("get", "service", "redis-master", nsFlag, "-o", "jsonpath={.spec.ports[0].port}")
|
||||
|
||||
By("applying the same configuration")
|
||||
framework.RunKubectlOrDieInput(string(serviceJson[:]), "apply", "-f", "-", nsFlag)
|
||||
|
||||
By("getting the nodePort after applying configuration")
|
||||
currentNodePort := framework.RunKubectlOrDie("get", "service", "redis-master", nsFlag, "-o", "jsonpath={.spec.ports[0].nodePort}")
|
||||
By("getting the port after applying configuration")
|
||||
currentNodePort := framework.RunKubectlOrDie("get", "service", "redis-master", nsFlag, "-o", "jsonpath={.spec.ports[0].port}")
|
||||
|
||||
By("checking the result")
|
||||
if originalNodePort != currentNodePort {
|
||||
framework.Failf("nodePort should keep the same")
|
||||
framework.Failf("port should keep the same")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -181,7 +181,7 @@ Kubectl alpha client Kubectl run ScheduledJob should create a ScheduledJob,karga
|
||||
Kubectl client Guestbook application should create and stop a working application,pwittrock,0
|
||||
Kubectl client Kubectl api-versions should check if v1 is in available api versions,pwittrock,0
|
||||
Kubectl client Kubectl apply should apply a new configuration to an existing RC,pwittrock,0
|
||||
Kubectl client Kubectl apply should reuse nodePort when apply to an existing SVC,pwittrock,0
|
||||
Kubectl client Kubectl apply should reuse port when apply to an existing SVC,deads2k,0
|
||||
Kubectl client Kubectl cluster-info should check if Kubernetes master services is included in cluster-info,pwittrock,0
|
||||
Kubectl client Kubectl create quota should create a quota with scopes,jdef,1
|
||||
Kubectl client Kubectl create quota should create a quota without scopes,xiang90,1
|
||||
|
|
Loading…
Reference in New Issue
Block a user