client_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package client
  14. import (
  15. "context"
  16. "fmt"
  17. "log"
  18. "reflect"
  19. rt "runtime"
  20. "sync"
  21. "testing"
  22. "time"
  23. v1 "k8s.io/api/core/v1"
  24. apierrors "k8s.io/apimachinery/pkg/api/errors"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. "k8s.io/apimachinery/pkg/fields"
  27. "k8s.io/apimachinery/pkg/labels"
  28. "k8s.io/apimachinery/pkg/runtime"
  29. "k8s.io/apimachinery/pkg/runtime/schema"
  30. "k8s.io/apimachinery/pkg/types"
  31. "k8s.io/apimachinery/pkg/util/wait"
  32. "k8s.io/apimachinery/pkg/watch"
  33. clientset "k8s.io/client-go/kubernetes"
  34. "k8s.io/component-base/version"
  35. kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
  36. "k8s.io/kubernetes/pkg/api/legacyscheme"
  37. "k8s.io/kubernetes/test/integration/framework"
  38. imageutils "k8s.io/kubernetes/test/utils/image"
  39. )
  40. func TestClient(t *testing.T) {
  41. result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
  42. defer result.TearDownFn()
  43. client := clientset.NewForConfigOrDie(result.ClientConfig)
  44. info, err := client.Discovery().ServerVersion()
  45. if err != nil {
  46. t.Fatalf("unexpected error: %v", err)
  47. }
  48. if e, a := version.Get(), *info; !reflect.DeepEqual(e, a) {
  49. t.Errorf("expected %#v, got %#v", e, a)
  50. }
  51. pods, err := client.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
  52. if err != nil {
  53. t.Fatalf("unexpected error: %v", err)
  54. }
  55. if len(pods.Items) != 0 {
  56. t.Errorf("expected no pods, got %#v", pods)
  57. }
  58. // get a validation error
  59. pod := &v1.Pod{
  60. ObjectMeta: metav1.ObjectMeta{
  61. GenerateName: "test",
  62. Namespace: "default",
  63. },
  64. Spec: v1.PodSpec{
  65. Containers: []v1.Container{
  66. {
  67. Name: "test",
  68. },
  69. },
  70. },
  71. }
  72. got, err := client.CoreV1().Pods("default").Create(context.TODO(), pod, metav1.CreateOptions{})
  73. if err == nil {
  74. t.Fatalf("unexpected non-error: %v", got)
  75. }
  76. // get a created pod
  77. pod.Spec.Containers[0].Image = "an-image"
  78. got, err = client.CoreV1().Pods("default").Create(context.TODO(), pod, metav1.CreateOptions{})
  79. if err != nil {
  80. t.Fatalf("unexpected error: %v", err)
  81. }
  82. if got.Name == "" {
  83. t.Errorf("unexpected empty pod Name %v", got)
  84. }
  85. // pod is shown, but not scheduled
  86. pods, err = client.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
  87. if err != nil {
  88. t.Fatalf("unexpected error: %v", err)
  89. }
  90. if len(pods.Items) != 1 {
  91. t.Errorf("expected one pod, got %#v", pods)
  92. }
  93. actual := pods.Items[0]
  94. if actual.Name != got.Name {
  95. t.Errorf("expected pod %#v, got %#v", got, actual)
  96. }
  97. if actual.Spec.NodeName != "" {
  98. t.Errorf("expected pod to be unscheduled, got %#v", actual)
  99. }
  100. }
  101. func TestAtomicPut(t *testing.T) {
  102. result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
  103. defer result.TearDownFn()
  104. c := clientset.NewForConfigOrDie(result.ClientConfig)
  105. rcBody := v1.ReplicationController{
  106. TypeMeta: metav1.TypeMeta{
  107. APIVersion: c.CoreV1().RESTClient().APIVersion().String(),
  108. },
  109. ObjectMeta: metav1.ObjectMeta{
  110. Name: "atomicrc",
  111. Namespace: "default",
  112. Labels: map[string]string{
  113. "name": "atomicrc",
  114. },
  115. },
  116. Spec: v1.ReplicationControllerSpec{
  117. Replicas: func(i int32) *int32 { return &i }(0),
  118. Selector: map[string]string{
  119. "foo": "bar",
  120. },
  121. Template: &v1.PodTemplateSpec{
  122. ObjectMeta: metav1.ObjectMeta{
  123. Labels: map[string]string{
  124. "foo": "bar",
  125. },
  126. },
  127. Spec: v1.PodSpec{
  128. Containers: []v1.Container{
  129. {Name: "name", Image: "image"},
  130. },
  131. },
  132. },
  133. },
  134. }
  135. rcs := c.CoreV1().ReplicationControllers("default")
  136. rc, err := rcs.Create(context.TODO(), &rcBody, metav1.CreateOptions{})
  137. if err != nil {
  138. t.Fatalf("Failed creating atomicRC: %v", err)
  139. }
  140. testLabels := labels.Set{
  141. "foo": "bar",
  142. }
  143. for i := 0; i < 5; i++ {
  144. // a: z, b: y, etc...
  145. testLabels[string([]byte{byte('a' + i)})] = string([]byte{byte('z' - i)})
  146. }
  147. var wg sync.WaitGroup
  148. wg.Add(len(testLabels))
  149. for label, value := range testLabels {
  150. go func(l, v string) {
  151. defer wg.Done()
  152. for {
  153. tmpRC, err := rcs.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  154. if err != nil {
  155. t.Errorf("Error getting atomicRC: %v", err)
  156. continue
  157. }
  158. if tmpRC.Spec.Selector == nil {
  159. tmpRC.Spec.Selector = map[string]string{l: v}
  160. tmpRC.Spec.Template.Labels = map[string]string{l: v}
  161. } else {
  162. tmpRC.Spec.Selector[l] = v
  163. tmpRC.Spec.Template.Labels[l] = v
  164. }
  165. _, err = rcs.Update(context.TODO(), tmpRC, metav1.UpdateOptions{})
  166. if err != nil {
  167. if apierrors.IsConflict(err) {
  168. // This is what we expect.
  169. continue
  170. }
  171. t.Errorf("Unexpected error putting atomicRC: %v", err)
  172. continue
  173. }
  174. return
  175. }
  176. }(label, value)
  177. }
  178. wg.Wait()
  179. rc, err = rcs.Get(context.TODO(), rc.Name, metav1.GetOptions{})
  180. if err != nil {
  181. t.Fatalf("Failed getting atomicRC after writers are complete: %v", err)
  182. }
  183. if !reflect.DeepEqual(testLabels, labels.Set(rc.Spec.Selector)) {
  184. t.Errorf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, rc.Spec.Selector)
  185. }
  186. }
  187. func TestPatch(t *testing.T) {
  188. result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
  189. defer result.TearDownFn()
  190. c := clientset.NewForConfigOrDie(result.ClientConfig)
  191. name := "patchpod"
  192. resource := "pods"
  193. podBody := v1.Pod{
  194. TypeMeta: metav1.TypeMeta{
  195. APIVersion: c.CoreV1().RESTClient().APIVersion().String(),
  196. },
  197. ObjectMeta: metav1.ObjectMeta{
  198. Name: name,
  199. Namespace: "default",
  200. Labels: map[string]string{},
  201. },
  202. Spec: v1.PodSpec{
  203. Containers: []v1.Container{
  204. {Name: "name", Image: "image"},
  205. },
  206. },
  207. }
  208. pods := c.CoreV1().Pods("default")
  209. _, err := pods.Create(context.TODO(), &podBody, metav1.CreateOptions{})
  210. if err != nil {
  211. t.Fatalf("Failed creating patchpods: %v", err)
  212. }
  213. patchBodies := map[schema.GroupVersion]map[types.PatchType]struct {
  214. AddLabelBody []byte
  215. RemoveLabelBody []byte
  216. RemoveAllLabelsBody []byte
  217. }{
  218. v1.SchemeGroupVersion: {
  219. types.JSONPatchType: {
  220. []byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`),
  221. []byte(`[{"op":"remove","path":"/metadata/labels/foo"}]`),
  222. []byte(`[{"op":"remove","path":"/metadata/labels"}]`),
  223. },
  224. types.MergePatchType: {
  225. []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`),
  226. []byte(`{"metadata":{"labels":{"foo":null}}}`),
  227. []byte(`{"metadata":{"labels":null}}`),
  228. },
  229. types.StrategicMergePatchType: {
  230. []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`),
  231. []byte(`{"metadata":{"labels":{"foo":null}}}`),
  232. []byte(`{"metadata":{"labels":{"$patch":"replace"}}}`),
  233. },
  234. },
  235. }
  236. pb := patchBodies[c.CoreV1().RESTClient().APIVersion()]
  237. execPatch := func(pt types.PatchType, body []byte) error {
  238. result := c.CoreV1().RESTClient().Patch(pt).
  239. Resource(resource).
  240. Namespace("default").
  241. Name(name).
  242. Body(body).
  243. Do(context.TODO())
  244. if result.Error() != nil {
  245. return result.Error()
  246. }
  247. // trying to chase flakes, this should give us resource versions of objects as we step through
  248. jsonObj, err := result.Raw()
  249. if err != nil {
  250. t.Log(err)
  251. } else {
  252. t.Logf("%v", string(jsonObj))
  253. }
  254. return nil
  255. }
  256. for k, v := range pb {
  257. // add label
  258. err := execPatch(k, v.AddLabelBody)
  259. if err != nil {
  260. t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
  261. }
  262. pod, err := pods.Get(context.TODO(), name, metav1.GetOptions{})
  263. if err != nil {
  264. t.Fatalf("Failed getting patchpod: %v", err)
  265. }
  266. if len(pod.Labels) != 2 || pod.Labels["foo"] != "bar" || pod.Labels["baz"] != "qux" {
  267. t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels)
  268. }
  269. // remove one label
  270. err = execPatch(k, v.RemoveLabelBody)
  271. if err != nil {
  272. t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
  273. }
  274. pod, err = pods.Get(context.TODO(), name, metav1.GetOptions{})
  275. if err != nil {
  276. t.Fatalf("Failed getting patchpod: %v", err)
  277. }
  278. if len(pod.Labels) != 1 || pod.Labels["baz"] != "qux" {
  279. t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels)
  280. }
  281. // remove all labels
  282. err = execPatch(k, v.RemoveAllLabelsBody)
  283. if err != nil {
  284. t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
  285. }
  286. pod, err = pods.Get(context.TODO(), name, metav1.GetOptions{})
  287. if err != nil {
  288. t.Fatalf("Failed getting patchpod: %v", err)
  289. }
  290. if pod.Labels != nil {
  291. t.Errorf("Failed remove all labels from patchpod with patch type %s: %v", k, pod.Labels)
  292. }
  293. }
  294. }
  295. func TestPatchWithCreateOnUpdate(t *testing.T) {
  296. result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
  297. defer result.TearDownFn()
  298. c := clientset.NewForConfigOrDie(result.ClientConfig)
  299. endpointTemplate := &v1.Endpoints{
  300. ObjectMeta: metav1.ObjectMeta{
  301. Name: "patchendpoint",
  302. Namespace: "default",
  303. },
  304. Subsets: []v1.EndpointSubset{
  305. {
  306. Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
  307. Ports: []v1.EndpointPort{{Port: 80, Protocol: v1.ProtocolTCP}},
  308. },
  309. },
  310. }
  311. patchEndpoint := func(json []byte) (runtime.Object, error) {
  312. return c.CoreV1().RESTClient().Patch(types.MergePatchType).Resource("endpoints").Namespace("default").Name("patchendpoint").Body(json).Do(context.TODO()).Get()
  313. }
  314. // Make sure patch doesn't get to CreateOnUpdate
  315. {
  316. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
  317. if err != nil {
  318. t.Fatalf("Failed creating endpoint JSON: %v", err)
  319. }
  320. if obj, err := patchEndpoint(endpointJSON); !apierrors.IsNotFound(err) {
  321. t.Errorf("Expected notfound creating from patch, got error=%v and object: %#v", err, obj)
  322. }
  323. }
  324. // Create the endpoint (endpoints set AllowCreateOnUpdate=true) to get a UID and resource version
  325. createdEndpoint, err := c.CoreV1().Endpoints("default").Update(context.TODO(), endpointTemplate, metav1.UpdateOptions{})
  326. if err != nil {
  327. t.Fatalf("Failed creating endpoint: %v", err)
  328. }
  329. // Make sure identity patch is accepted
  330. {
  331. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), createdEndpoint)
  332. if err != nil {
  333. t.Fatalf("Failed creating endpoint JSON: %v", err)
  334. }
  335. if _, err := patchEndpoint(endpointJSON); err != nil {
  336. t.Errorf("Failed patching endpoint: %v", err)
  337. }
  338. }
  339. // Make sure patch complains about a mismatched resourceVersion
  340. {
  341. endpointTemplate.Name = ""
  342. endpointTemplate.UID = ""
  343. endpointTemplate.ResourceVersion = "1"
  344. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
  345. if err != nil {
  346. t.Fatalf("Failed creating endpoint JSON: %v", err)
  347. }
  348. if _, err := patchEndpoint(endpointJSON); !apierrors.IsConflict(err) {
  349. t.Errorf("Expected error, got %#v", err)
  350. }
  351. }
  352. // Make sure patch complains about mutating the UID
  353. {
  354. endpointTemplate.Name = ""
  355. endpointTemplate.UID = "abc"
  356. endpointTemplate.ResourceVersion = ""
  357. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
  358. if err != nil {
  359. t.Fatalf("Failed creating endpoint JSON: %v", err)
  360. }
  361. if _, err := patchEndpoint(endpointJSON); !apierrors.IsInvalid(err) {
  362. t.Errorf("Expected error, got %#v", err)
  363. }
  364. }
  365. // Make sure patch complains about a mismatched name
  366. {
  367. endpointTemplate.Name = "changedname"
  368. endpointTemplate.UID = ""
  369. endpointTemplate.ResourceVersion = ""
  370. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
  371. if err != nil {
  372. t.Fatalf("Failed creating endpoint JSON: %v", err)
  373. }
  374. if _, err := patchEndpoint(endpointJSON); !apierrors.IsBadRequest(err) {
  375. t.Errorf("Expected error, got %#v", err)
  376. }
  377. }
  378. // Make sure patch containing originally submitted JSON is accepted
  379. {
  380. endpointTemplate.Name = ""
  381. endpointTemplate.UID = ""
  382. endpointTemplate.ResourceVersion = ""
  383. endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
  384. if err != nil {
  385. t.Fatalf("Failed creating endpoint JSON: %v", err)
  386. }
  387. if _, err := patchEndpoint(endpointJSON); err != nil {
  388. t.Errorf("Failed patching endpoint: %v", err)
  389. }
  390. }
  391. }
  392. func TestAPIVersions(t *testing.T) {
  393. result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
  394. defer result.TearDownFn()
  395. c := clientset.NewForConfigOrDie(result.ClientConfig)
  396. clientVersion := c.CoreV1().RESTClient().APIVersion().String()
  397. g, err := c.Discovery().ServerGroups()
  398. if err != nil {
  399. t.Fatalf("Failed to get api versions: %v", err)
  400. }
  401. versions := metav1.ExtractGroupVersions(g)
  402. // Verify that the server supports the API version used by the client.
  403. for _, version := range versions {
  404. if version == clientVersion {
  405. return
  406. }
  407. }
  408. t.Errorf("Server does not support APIVersion used by client. Server supported APIVersions: '%v', client APIVersion: '%v'", versions, clientVersion)
  409. }
  410. func TestSingleWatch(t *testing.T) {
  411. result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
  412. defer result.TearDownFn()
  413. client := clientset.NewForConfigOrDie(result.ClientConfig)
  414. mkEvent := func(i int) *v1.Event {
  415. name := fmt.Sprintf("event-%v", i)
  416. return &v1.Event{
  417. ObjectMeta: metav1.ObjectMeta{
  418. Namespace: "default",
  419. Name: name,
  420. },
  421. InvolvedObject: v1.ObjectReference{
  422. Namespace: "default",
  423. Name: name,
  424. },
  425. Reason: fmt.Sprintf("event %v", i),
  426. }
  427. }
  428. rv1 := ""
  429. for i := 0; i < 10; i++ {
  430. event := mkEvent(i)
  431. got, err := client.CoreV1().Events("default").Create(context.TODO(), event, metav1.CreateOptions{})
  432. if err != nil {
  433. t.Fatalf("Failed creating event %#q: %v", event, err)
  434. }
  435. if rv1 == "" {
  436. rv1 = got.ResourceVersion
  437. if rv1 == "" {
  438. t.Fatal("did not get a resource version.")
  439. }
  440. }
  441. t.Logf("Created event %#v", got.ObjectMeta)
  442. }
  443. w, err := client.CoreV1().RESTClient().Get().
  444. Namespace("default").
  445. Resource("events").
  446. VersionedParams(&metav1.ListOptions{
  447. ResourceVersion: rv1,
  448. Watch: true,
  449. FieldSelector: fields.OneTermEqualSelector("metadata.name", "event-9").String(),
  450. }, metav1.ParameterCodec).
  451. Watch(context.TODO())
  452. if err != nil {
  453. t.Fatalf("Failed watch: %v", err)
  454. }
  455. defer w.Stop()
  456. select {
  457. case <-time.After(wait.ForeverTestTimeout):
  458. t.Fatalf("watch took longer than %s", wait.ForeverTestTimeout.String())
  459. case got, ok := <-w.ResultChan():
  460. if !ok {
  461. t.Fatal("Watch channel closed unexpectedly.")
  462. }
  463. // We expect to see an ADD of event-9 and only event-9. (This
  464. // catches a bug where all the events would have been sent down
  465. // the channel.)
  466. if e, a := watch.Added, got.Type; e != a {
  467. t.Errorf("Wanted %v, got %v", e, a)
  468. }
  469. switch o := got.Object.(type) {
  470. case *v1.Event:
  471. if e, a := "event-9", o.Name; e != a {
  472. t.Errorf("Wanted %v, got %v", e, a)
  473. }
  474. default:
  475. t.Fatalf("Unexpected watch event containing object %#q", got)
  476. }
  477. }
  478. }
  479. func TestMultiWatch(t *testing.T) {
  480. // Disable this test as long as it demonstrates a problem.
  481. // TODO: Re-enable this test when we get #6059 resolved.
  482. t.Skip()
  483. const watcherCount = 50
  484. rt.GOMAXPROCS(watcherCount)
  485. result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
  486. defer result.TearDownFn()
  487. client := clientset.NewForConfigOrDie(result.ClientConfig)
  488. dummyEvent := func(i int) *v1.Event {
  489. name := fmt.Sprintf("unrelated-%v", i)
  490. return &v1.Event{
  491. ObjectMeta: metav1.ObjectMeta{
  492. Name: fmt.Sprintf("%v.%x", name, time.Now().UnixNano()),
  493. Namespace: "default",
  494. },
  495. InvolvedObject: v1.ObjectReference{
  496. Name: name,
  497. Namespace: "default",
  498. },
  499. Reason: fmt.Sprintf("unrelated change %v", i),
  500. }
  501. }
  502. type timePair struct {
  503. t time.Time
  504. name string
  505. }
  506. receivedTimes := make(chan timePair, watcherCount*2)
  507. watchesStarted := sync.WaitGroup{}
  508. // make a bunch of pods and watch them
  509. for i := 0; i < watcherCount; i++ {
  510. watchesStarted.Add(1)
  511. name := fmt.Sprintf("multi-watch-%v", i)
  512. got, err := client.CoreV1().Pods("default").Create(context.TODO(), &v1.Pod{
  513. ObjectMeta: metav1.ObjectMeta{
  514. Name: name,
  515. Labels: labels.Set{"watchlabel": name},
  516. },
  517. Spec: v1.PodSpec{
  518. Containers: []v1.Container{{
  519. Name: "pause",
  520. Image: imageutils.GetPauseImageName(),
  521. }},
  522. },
  523. }, metav1.CreateOptions{})
  524. if err != nil {
  525. t.Fatalf("Couldn't make %v: %v", name, err)
  526. }
  527. go func(name, rv string) {
  528. options := metav1.ListOptions{
  529. LabelSelector: labels.Set{"watchlabel": name}.AsSelector().String(),
  530. ResourceVersion: rv,
  531. }
  532. w, err := client.CoreV1().Pods("default").Watch(context.TODO(), options)
  533. if err != nil {
  534. panic(fmt.Sprintf("watch error for %v: %v", name, err))
  535. }
  536. defer w.Stop()
  537. watchesStarted.Done()
  538. e, ok := <-w.ResultChan() // should get the update (that we'll do below)
  539. if !ok {
  540. panic(fmt.Sprintf("%v ended early?", name))
  541. }
  542. if e.Type != watch.Modified {
  543. panic(fmt.Sprintf("Got unexpected watch notification:\n%v: %+v %+v", name, e, e.Object))
  544. }
  545. receivedTimes <- timePair{time.Now(), name}
  546. }(name, got.ObjectMeta.ResourceVersion)
  547. }
  548. log.Printf("%v: %v pods made and watchers started", time.Now(), watcherCount)
  549. // wait for watches to start before we start spamming the system with
  550. // objects below, otherwise we'll hit the watch window restriction.
  551. watchesStarted.Wait()
  552. const (
  553. useEventsAsUnrelatedType = false
  554. usePodsAsUnrelatedType = true
  555. )
  556. // make a bunch of unrelated changes in parallel
  557. if useEventsAsUnrelatedType {
  558. const unrelatedCount = 3000
  559. var wg sync.WaitGroup
  560. defer wg.Wait()
  561. changeToMake := make(chan int, unrelatedCount*2)
  562. changeMade := make(chan int, unrelatedCount*2)
  563. go func() {
  564. for i := 0; i < unrelatedCount; i++ {
  565. changeToMake <- i
  566. }
  567. close(changeToMake)
  568. }()
  569. for i := 0; i < 50; i++ {
  570. wg.Add(1)
  571. go func() {
  572. defer wg.Done()
  573. for {
  574. i, ok := <-changeToMake
  575. if !ok {
  576. return
  577. }
  578. if _, err := client.CoreV1().Events("default").Create(context.TODO(), dummyEvent(i), metav1.CreateOptions{}); err != nil {
  579. panic(fmt.Sprintf("couldn't make an event: %v", err))
  580. }
  581. changeMade <- i
  582. }
  583. }()
  584. }
  585. for i := 0; i < 2000; i++ {
  586. <-changeMade
  587. if (i+1)%50 == 0 {
  588. log.Printf("%v: %v unrelated changes made", time.Now(), i+1)
  589. }
  590. }
  591. }
  592. if usePodsAsUnrelatedType {
  593. const unrelatedCount = 3000
  594. var wg sync.WaitGroup
  595. defer wg.Wait()
  596. changeToMake := make(chan int, unrelatedCount*2)
  597. changeMade := make(chan int, unrelatedCount*2)
  598. go func() {
  599. for i := 0; i < unrelatedCount; i++ {
  600. changeToMake <- i
  601. }
  602. close(changeToMake)
  603. }()
  604. for i := 0; i < 50; i++ {
  605. wg.Add(1)
  606. go func() {
  607. defer wg.Done()
  608. for {
  609. i, ok := <-changeToMake
  610. if !ok {
  611. return
  612. }
  613. name := fmt.Sprintf("unrelated-%v", i)
  614. _, err := client.CoreV1().Pods("default").Create(context.TODO(), &v1.Pod{
  615. ObjectMeta: metav1.ObjectMeta{
  616. Name: name,
  617. },
  618. Spec: v1.PodSpec{
  619. Containers: []v1.Container{{
  620. Name: "nothing",
  621. Image: imageutils.GetPauseImageName(),
  622. }},
  623. },
  624. }, metav1.CreateOptions{})
  625. if err != nil {
  626. panic(fmt.Sprintf("couldn't make unrelated pod: %v", err))
  627. }
  628. changeMade <- i
  629. }
  630. }()
  631. }
  632. for i := 0; i < 2000; i++ {
  633. <-changeMade
  634. if (i+1)%50 == 0 {
  635. log.Printf("%v: %v unrelated changes made", time.Now(), i+1)
  636. }
  637. }
  638. }
  639. // Now we still have changes being made in parallel, but at least 1000 have been made.
  640. // Make some updates to send down the watches.
  641. sentTimes := make(chan timePair, watcherCount*2)
  642. for i := 0; i < watcherCount; i++ {
  643. go func(i int) {
  644. name := fmt.Sprintf("multi-watch-%v", i)
  645. pod, err := client.CoreV1().Pods("default").Get(context.TODO(), name, metav1.GetOptions{})
  646. if err != nil {
  647. panic(fmt.Sprintf("Couldn't get %v: %v", name, err))
  648. }
  649. pod.Spec.Containers[0].Image = imageutils.GetPauseImageName()
  650. sentTimes <- timePair{time.Now(), name}
  651. if _, err := client.CoreV1().Pods("default").Update(context.TODO(), pod, metav1.UpdateOptions{}); err != nil {
  652. panic(fmt.Sprintf("Couldn't make %v: %v", name, err))
  653. }
  654. }(i)
  655. }
  656. sent := map[string]time.Time{}
  657. for i := 0; i < watcherCount; i++ {
  658. tp := <-sentTimes
  659. sent[tp.name] = tp.t
  660. }
  661. log.Printf("all changes made")
  662. dur := map[string]time.Duration{}
  663. for i := 0; i < watcherCount; i++ {
  664. tp := <-receivedTimes
  665. delta := tp.t.Sub(sent[tp.name])
  666. dur[tp.name] = delta
  667. log.Printf("%v: %v", tp.name, delta)
  668. }
  669. log.Printf("all watches ended")
  670. t.Errorf("durations: %v", dur)
  671. }
  672. func runSelfLinkTestOnNamespace(t *testing.T, c clientset.Interface, namespace string) {
  673. podBody := v1.Pod{
  674. ObjectMeta: metav1.ObjectMeta{
  675. Name: "selflinktest",
  676. Namespace: namespace,
  677. Labels: map[string]string{
  678. "name": "selflinktest",
  679. },
  680. },
  681. Spec: v1.PodSpec{
  682. Containers: []v1.Container{
  683. {Name: "name", Image: "image"},
  684. },
  685. },
  686. }
  687. pod, err := c.CoreV1().Pods(namespace).Create(context.TODO(), &podBody, metav1.CreateOptions{})
  688. if err != nil {
  689. t.Fatalf("Failed creating selflinktest pod: %v", err)
  690. }
  691. if err = c.CoreV1().RESTClient().Get().RequestURI(pod.SelfLink).Do(context.TODO()).Into(pod); err != nil {
  692. t.Errorf("Failed listing pod with supplied self link '%v': %v", pod.SelfLink, err)
  693. }
  694. podList, err := c.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
  695. if err != nil {
  696. t.Errorf("Failed listing pods: %v", err)
  697. }
  698. if err = c.CoreV1().RESTClient().Get().RequestURI(podList.SelfLink).Do(context.TODO()).Into(podList); err != nil {
  699. t.Errorf("Failed listing pods with supplied self link '%v': %v", podList.SelfLink, err)
  700. }
  701. found := false
  702. for i := range podList.Items {
  703. item := &podList.Items[i]
  704. if item.Name != "selflinktest" {
  705. continue
  706. }
  707. found = true
  708. err = c.CoreV1().RESTClient().Get().RequestURI(item.SelfLink).Do(context.TODO()).Into(pod)
  709. if err != nil {
  710. t.Errorf("Failed listing pod with supplied self link '%v': %v", item.SelfLink, err)
  711. }
  712. break
  713. }
  714. if !found {
  715. t.Errorf("never found selflinktest pod in namespace %s", namespace)
  716. }
  717. }
  718. func TestSelfLinkOnNamespace(t *testing.T) {
  719. result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
  720. defer result.TearDownFn()
  721. c := clientset.NewForConfigOrDie(result.ClientConfig)
  722. runSelfLinkTestOnNamespace(t, c, "default")
  723. }