func TestPodReadOnlyFilesystem(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() isReadOnly := true ns := framework.CreateTestingNamespace("pod-readonly-root", s, t) defer framework.DeleteTestingNamespace(ns, s, t) client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "xxx", }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "fake-name", Image: "fakeimage", SecurityContext: &api.SecurityContext{ ReadOnlyRootFilesystem: &isReadOnly, }, }, }, }, } if _, err := client.Pods(ns.Name).Create(pod); err != nil { t.Errorf("Failed to create pod: %v", err) } deletePodOrErrorf(t, client, ns.Name, pod.Name) }
// This test simulates the case where an object is created with an owner that // doesn't exist. It verifies the GC will delete such an object. func TestCreateWithNonExistentOwner(t *testing.T) { s, gc, clientSet := setup(t) defer s.Close() ns := framework.CreateTestingNamespace("gc-non-existing-owner", s, t) defer framework.DeleteTestingNamespace(ns, s, t) podClient := clientSet.Core().Pods(ns.Name) pod := newPod(garbageCollectedPodName, ns.Name, []metav1.OwnerReference{{UID: "doesn't matter", Name: toBeDeletedRCName}}) _, err := podClient.Create(pod) if err != nil { t.Fatalf("Failed to create Pod: %v", err) } // set up watch pods, err := podClient.List(v1.ListOptions{}) if err != nil { t.Fatalf("Failed to list pods: %v", err) } if len(pods.Items) != 1 { t.Fatalf("Expect only 1 pod") } stopCh := make(chan struct{}) go gc.Run(5, stopCh) defer close(stopCh) // wait for the garbage collector to delete the pod if err := integration.WaitForPodToDisappear(podClient, garbageCollectedPodName, 5*time.Second, 30*time.Second); err != nil { t.Fatalf("expect pod %s to be garbage collected, got err= %v", garbageCollectedPodName, err) } }
func TestAuthModeAlwaysDeny(t *testing.T) { // Set up a master masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.Authorizer = apiserver.NewAlwaysDenyAuthorizer() _, s := framework.RunAMaster(masterConfig) defer s.Close() ns := framework.CreateTestingNamespace("auth-always-deny", s, t) defer framework.DeleteTestingNamespace(ns, s, t) transport := http.DefaultTransport for _, r := range getTestRequests(ns.Name) { bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } if resp.StatusCode != http.StatusForbidden { t.Logf("case %v", r) t.Errorf("Expected status Forbidden but got status %v", resp.Status) } }() } }
func TestPersistentVolumeDeleter(t *testing.T) { glog.V(2).Infof("TestPersistentVolumeDeleter started") _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("pv-deleter", s, t) defer framework.DeleteTestingNamespace(ns, s, t) testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s, defaultSyncPeriod) defer watchPV.Stop() defer watchPVC.Stop() // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (PersistenceVolumes). defer testClient.Core().PersistentVolumes().DeleteCollection(nil, api.ListOptions{}) stopCh := make(chan struct{}) ctrl.Run(stopCh) defer close(stopCh) // This PV will be claimed, released, and deleted. pv := createPV("fake-pv-deleter", "/tmp/foo", "10G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimDelete) pvc := createPVC("fake-pvc-deleter", ns.Name, "5G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}) _, err := testClient.PersistentVolumes().Create(pv) if err != nil { t.Errorf("Failed to create PersistentVolume: %v", err) } glog.V(2).Infof("TestPersistentVolumeDeleter pv created") _, err = testClient.PersistentVolumeClaims(ns.Name).Create(pvc) if err != nil { t.Errorf("Failed to create PersistentVolumeClaim: %v", err) } glog.V(2).Infof("TestPersistentVolumeDeleter pvc created") waitForPersistentVolumePhase(testClient, pv.Name, watchPV, api.VolumeBound) glog.V(2).Infof("TestPersistentVolumeDeleter pv bound") waitForPersistentVolumeClaimPhase(testClient, pvc.Name, ns.Name, watchPVC, api.ClaimBound) glog.V(2).Infof("TestPersistentVolumeDeleter pvc bound") // deleting a claim releases the volume, after which it can be recycled if err := testClient.PersistentVolumeClaims(ns.Name).Delete(pvc.Name, nil); err != nil { t.Errorf("error deleting claim %s", pvc.Name) } glog.V(2).Infof("TestPersistentVolumeDeleter pvc deleted") waitForPersistentVolumePhase(testClient, pv.Name, watchPV, api.VolumeReleased) glog.V(2).Infof("TestPersistentVolumeDeleter pv released") for { event := <-watchPV.ResultChan() if event.Type == watch.Deleted { break } } glog.V(2).Infof("TestPersistentVolumeDeleter pv deleted") }
// TestConfigMap tests apiserver-side behavior of creation of ConfigMaps and pods that consume them. func TestConfigMap(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}}) ns := framework.CreateTestingNamespace("config-map", s, t) defer framework.DeleteTestingNamespace(ns, s, t) DoTestConfigMap(t, client, ns) }
// TestStorageClasses tests apiserver-side behavior of creation of storage class objects and their use by pvcs. func TestStorageClasses(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}) ns := framework.CreateTestingNamespace("storageclass", s, t) defer framework.DeleteTestingNamespace(ns, s, t) DoTestStorageClasses(t, client, ns) }
// TestSecrets tests apiserver-side behavior of creation of secret objects and their use by pods. func TestSecrets(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) ns := framework.CreateTestingNamespace("secret", s, t) defer framework.DeleteTestingNamespace(ns, s, t) DoTestSecrets(t, client, ns) }
func TestSelfLinkOnNamespace(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("selflink", s, t) defer framework.DeleteTestingNamespace(ns, s, t) c := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}}) runSelfLinkTestOnNamespace(t, c, ns.Name) }
func TestSelfLinkOnNamespace(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("selflink", s, t) defer framework.DeleteTestingNamespace(ns, s, t) c := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) runSelfLinkTestOnNamespace(t, c, ns.Name) }
func TestPersistentVolumeRecycler(t *testing.T) { glog.V(2).Infof("TestPersistentVolumeRecycler started") _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("pv-recycler", s, t) defer framework.DeleteTestingNamespace(ns, s, t) testClient, ctrl, watchPV, watchPVC := createClients(ns, t, s) defer watchPV.Stop() defer watchPVC.Stop() // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (PersistenceVolumes). defer testClient.Core().PersistentVolumes().DeleteCollection(nil, api.ListOptions{}) ctrl.Run() defer ctrl.Stop() // This PV will be claimed, released, and recycled. pv := createPV("fake-pv-recycler", "/tmp/foo", "10G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, api.PersistentVolumeReclaimRecycle) pvc := createPVC("fake-pvc-recycler", ns.Name, "5G", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}) _, err := testClient.PersistentVolumes().Create(pv) if err != nil { t.Errorf("Failed to create PersistentVolume: %v", err) } glog.V(2).Infof("TestPersistentVolumeRecycler pvc created") _, err = testClient.PersistentVolumeClaims(ns.Name).Create(pvc) if err != nil { t.Errorf("Failed to create PersistentVolumeClaim: %v", err) } glog.V(2).Infof("TestPersistentVolumeRecycler pvc created") // wait until the controller pairs the volume and claim waitForPersistentVolumePhase(testClient, pv.Name, watchPV, api.VolumeBound) glog.V(2).Infof("TestPersistentVolumeRecycler pv bound") waitForPersistentVolumeClaimPhase(testClient, pvc.Name, ns.Name, watchPVC, api.ClaimBound) glog.V(2).Infof("TestPersistentVolumeRecycler pvc bound") // deleting a claim releases the volume, after which it can be recycled if err := testClient.PersistentVolumeClaims(ns.Name).Delete(pvc.Name, nil); err != nil { t.Errorf("error deleting claim %s", pvc.Name) } glog.V(2).Infof("TestPersistentVolumeRecycler pvc deleted") waitForPersistentVolumePhase(testClient, pv.Name, watchPV, api.VolumeReleased) glog.V(2).Infof("TestPersistentVolumeRecycler pv released") waitForPersistentVolumePhase(testClient, pv.Name, watchPV, api.VolumeAvailable) glog.V(2).Infof("TestPersistentVolumeRecycler pv available") }
// TestReadOnlyAuthorization tests that authorization can be controlled // by namespace. func TestReadOnlyAuthorization(t *testing.T) { // This file has alice and bob in it. a := newAuthorizerWithContents(t, `{"readonly": true}`) // Set up a master masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.Authenticator = getTestTokenAuth() masterConfig.Authorizer = a _, s := framework.RunAMaster(masterConfig) defer s.Close() ns := framework.CreateTestingNamespace("auth-read-only", s, t) defer framework.DeleteTestingNamespace(ns, s, t) transport := http.DefaultTransport requests := []struct { verb string URL string body string statusCodes map[int]bool // allowed status codes. }{ {"POST", path("pods", ns.Name, ""), aPod, integration.Code403}, {"GET", path("pods", ns.Name, ""), "", integration.Code200}, {"GET", path("pods", api.NamespaceDefault, "a"), "", integration.Code404}, } for _, r := range requests { token := BobToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } if _, ok := r.statusCodes[resp.StatusCode]; !ok { t.Logf("case %v", r) t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) t.Errorf("Body: %v", string(b)) } }() } }
func TestUpdateSelectorToRemoveControllerRef(t *testing.T) { // We have pod1, pod2 and rs. rs.spec.replicas=2. At first rs.Selector // matches pod1 and pod2; change the selector to match only pod1. Verify // that rs creates one more pod, so there are 3 pods. Also verify that // pod2's controllerRef is cleared. s, rm, rsInformer, podInformer, clientSet := rmSetup(t, true) ns := framework.CreateTestingNamespace("rs-update-selector-to-remove-controllerref", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rs := newRS("rs", ns.Name, 2) pod1 := newMatchingPod("pod1", ns.Name) pod1.Labels["uniqueKey"] = "1" pod2 := newMatchingPod("pod2", ns.Name) pod2.Labels["uniqueKey"] = "2" createRSsPods(t, clientSet, []*v1beta1.ReplicaSet{rs}, []*v1.Pod{pod1, pod2}, ns.Name) stopCh := make(chan struct{}) go rsInformer.Run(stopCh) go podInformer.Run(stopCh) waitToObservePods(t, podInformer, 2) go rm.Run(5, stopCh) waitRSStable(t, clientSet, rs, ns.Name) // change the rs's selector to match both pods patch := `{"spec":{"selector":{"matchLabels": {"uniqueKey":"1"}},"template":{"metadata":{"labels":{"uniqueKey":"1"}}}}}` rsClient := clientSet.Extensions().ReplicaSets(ns.Name) rs, err := rsClient.Patch(rs.Name, api.StrategicMergePatchType, []byte(patch)) if err != nil { t.Fatalf("Failed to patch replica set: %v", err) } t.Logf("patched rs = %#v", rs) // wait for the rs to create one more pod if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { return verifyRemainingObjects(t, clientSet, ns.Name, 1, 3) }); err != nil { t.Fatal(err) } podClient := clientSet.Core().Pods(ns.Name) pod2, err = podClient.Get(pod2.Name) if err != nil { t.Fatalf("Failed to get pod2: %v", err) } if len(pod2.OwnerReferences) != 0 { t.Fatalf("ownerReferences of pod2 is not cleared, got %#v", pod2.OwnerReferences) } close(stopCh) }
// Benchmark pod listing by waiting on `Tasks` listers to list `Pods` pods via `Workers`. func BenchmarkPodListEtcd(b *testing.B) { b.StopTimer() m := framework.NewMasterComponents(&framework.Config{nil, true, false, 250.0, 500}) defer m.Stop(true, true) ns := framework.CreateTestingNamespace("benchmark-pod-list-etcd", s, t) defer framework.DeleteTestingNamespace(ns, s, t) numPods, numTasks, iter := getPods(b.N), getTasks(b.N), getIterations(b.N) podsPerNode := numPods / numTasks if podsPerNode < 1 { podsPerNode = 1 } startPodsOnNodes(ns.Name, numPods, numTasks, m.RestClient) // Stop the rc manager so it doesn't steal resources m.Stop(false, true) glog.Infof("Starting benchmark: b.N %d, pods %d, workers %d, podsPerNode %d", b.N, numPods, numTasks, podsPerNode) b.StartTimer() for i := 0; i < iter; i++ { framework.RunParallel(func(id int) error { now := time.Now() defer func() { glog.V(3).Infof("Worker %d: listing pods took %v", id, time.Since(now)) }() pods, err := m.ClientSet.Core().Pods(ns.Name).List(api.ListOptions{ LabelSelector: labels.Everything(), FieldSelector: fields.Everything(), }) if err != nil { return err } if len(pods.Items) < numPods { glog.Fatalf("List retrieved %d pods, which is less than %d", len(pods.Items), numPods) } return nil }, numTasks, Workers) } b.StopTimer() }
// This test simulates the case where an object is created with an owner that // doesn't exist. It verifies the GC will delete such an object. func TestCreateWithNonExistentOwner(t *testing.T) { glog.V(6).Infof("TestCreateWithNonExistentOwner starts") defer glog.V(6).Infof("TestCreateWithNonExistentOwner ends") s, gc, clientSet := setup(t) defer s.Close() ns := framework.CreateTestingNamespace("gc-non-existing-owner", s, t) defer framework.DeleteTestingNamespace(ns, s, t) oldEnableGarbageCollector := registry.EnableGarbageCollector registry.EnableGarbageCollector = true defer func() { registry.EnableGarbageCollector = oldEnableGarbageCollector }() podClient := clientSet.Core().Pods(ns.Name) pod := newPod(garbageCollectedPodName, ns.Name, []v1.OwnerReference{{UID: "doesn't matter", Name: toBeDeletedRCName}}) _, err := podClient.Create(pod) if err != nil { t.Fatalf("Failed to create Pod: %v", err) } // set up watch pods, err := podClient.List(api.ListOptions{}) if err != nil { t.Fatalf("Failed to list pods: %v", err) } if len(pods.Items) != 1 { t.Fatalf("Expect only 1 pod") } stopCh := make(chan struct{}) go gc.Run(5, stopCh) defer close(stopCh) // wait for the garbage collector to drain its queue if err := wait.Poll(10*time.Second, 120*time.Second, func() (bool, error) { return gc.QueuesDrained(), nil }); err != nil { t.Fatal(err) } t.Logf("garbage collector queues drained") if _, err := podClient.Get(garbageCollectedPodName); err == nil || !errors.IsNotFound(err) { t.Fatalf("expect pod %s to be garbage collected", garbageCollectedPodName) } }
func TestUpdateLabelToRemoveControllerRef(t *testing.T) { // We have pod1, pod2 and rc. rc.spec.replicas=2. At first rc.Selector // matches pod1 and pod2; change pod2's labels to non-matching. Verify // that rc creates one more pod, so there are 3 pods. Also verify that // pod2's controllerRef is cleared. s, rm, podInformer, clientSet := rmSetup(t, true) ns := framework.CreateTestingNamespace("update-label-to-remove-controllerref", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rc := newRC("rc", ns.Name, 2) pod1 := newMatchingPod("pod1", ns.Name) pod2 := newMatchingPod("pod2", ns.Name) createRCsPods(t, clientSet, []*v1.ReplicationController{rc}, []*v1.Pod{pod1, pod2}, ns.Name) stopCh := make(chan struct{}) go podInformer.Run(stopCh) go rm.Run(5, stopCh) waitRCStable(t, clientSet, rc, ns.Name) // change the rc's selector to match both pods patch := `{"metadata":{"labels":{"name":null}}}` podClient := clientSet.Core().Pods(ns.Name) pod2, err := podClient.Patch(pod2.Name, api.StrategicMergePatchType, []byte(patch)) if err != nil { t.Fatalf("Failed to patch pod2: %v", err) } t.Logf("patched pod2 = %#v", pod2) // wait for the rc to create one more pod if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { return verifyRemainingObjects(t, clientSet, ns.Name, 1, 3) }); err != nil { t.Fatal(err) } pod2, err = podClient.Get(pod2.Name) if err != nil { t.Fatalf("Failed to get pod2: %v", err) } if len(pod2.OwnerReferences) != 0 { t.Fatalf("ownerReferences of pod2 is not cleared, got %#v", pod2.OwnerReferences) } close(stopCh) }
// Benchmark pod listing by waiting on `Tasks` listers to list `Pods` pods via `Workers`. func BenchmarkPodList(b *testing.B) { b.StopTimer() m := framework.NewMasterComponents(&framework.Config{nil, true, false, 250.0, 500}) defer m.Stop(true, true) ns := framework.CreateTestingNamespace("benchmark-pod-list", s, t) defer framework.DeleteTestingNamespace(ns, s, t) numPods, numTasks, iter := getPods(b.N), getTasks(b.N), getIterations(b.N) podsPerNode := numPods / numTasks if podsPerNode < 1 { podsPerNode = 1 } glog.Infof("Starting benchmark: b.N %d, pods %d, workers %d, podsPerNode %d", b.N, numPods, numTasks, podsPerNode) startPodsOnNodes(ns.Name, numPods, numTasks, m.RestClient) // Stop the rc manager so it doesn't steal resources m.Stop(false, true) b.StartTimer() for i := 0; i < iter; i++ { framework.RunParallel(func(id int) error { host := fmt.Sprintf("host.%d", id) now := time.Now() defer func() { glog.V(3).Infof("Worker %d: Node %v listing pods took %v", id, host, time.Since(now)) }() if pods, err := m.RestClient.Pods(ns.Name).List( labels.Everything(), fields.OneTermEqualSelector(client.PodHost, host)); err != nil { return err } else if len(pods.Items) < podsPerNode { glog.Fatalf("List retrieved %d pods, which is less than %d", len(pods.Items), podsPerNode) } return nil }, numTasks, Workers) } b.StopTimer() }
// TestUnknownUserIsUnauthorized tests that a user who is unknown // to the authentication system get status code "Unauthorized". // An authorization module is installed in this scenario for integration // test purposes, but requests aren't expected to reach it. func TestUnknownUserIsUnauthorized(t *testing.T) { // This file has alice and bob in it. // Set up a master masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.Authenticator = getTestTokenAuth() masterConfig.Authorizer = allowAliceAuthorizer{} _, s := framework.RunAMaster(masterConfig) defer s.Close() ns := framework.CreateTestingNamespace("auth-unknown-unauthorized", s, t) defer framework.DeleteTestingNamespace(ns, s, t) transport := http.DefaultTransport for _, r := range getTestRequests(ns.Name) { token := UnknownToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } // Expect all of unauthenticated user's request to be "Unauthorized" if resp.StatusCode != http.StatusUnauthorized { t.Logf("case %v", r) t.Errorf("Expected status %v, but got %v", http.StatusUnauthorized, resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) t.Errorf("Body: %v", string(b)) } }() } }
func TestUpdateLabelToBeAdopted(t *testing.T) { // We have pod1, pod2 and rs. rs.spec.replicas=1. At first rs.Selector // matches pod1 only; change pod2's labels to be matching. Verify the RS // controller adopts pod2 and delete one of them, so there is only 1 pod // left. s, rm, rsInformer, podInformer, clientSet := rmSetup(t, true) ns := framework.CreateTestingNamespace("rs-update-label-to-be-adopted", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rs := newRS("rs", ns.Name, 1) // let rs's selector only matches pod1 rs.Spec.Selector.MatchLabels["uniqueKey"] = "1" rs.Spec.Template.Labels["uniqueKey"] = "1" pod1 := newMatchingPod("pod1", ns.Name) pod1.Labels["uniqueKey"] = "1" pod2 := newMatchingPod("pod2", ns.Name) pod2.Labels["uniqueKey"] = "2" createRSsPods(t, clientSet, []*v1beta1.ReplicaSet{rs}, []*v1.Pod{pod1, pod2}, ns.Name) stopCh := make(chan struct{}) go rsInformer.Run(stopCh) go podInformer.Run(stopCh) go rm.Run(5, stopCh) waitRSStable(t, clientSet, rs, ns.Name) // change the rs's selector to match both pods patch := `{"metadata":{"labels":{"uniqueKey":"1"}}}` podClient := clientSet.Core().Pods(ns.Name) pod2, err := podClient.Patch(pod2.Name, api.StrategicMergePatchType, []byte(patch)) if err != nil { t.Fatalf("Failed to patch pod2: %v", err) } t.Logf("patched pod2 = %#v", pod2) // wait for the rs to select both pods and delete one of them if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { return verifyRemainingObjects(t, clientSet, ns.Name, 1, 1) }); err != nil { t.Fatal(err) } close(stopCh) }
func TestUpdateSelectorToAdopt(t *testing.T) { // We have pod1, pod2 and rs. rs.spec.replicas=1. At first rs.Selector // matches pod1 only; change the selector to match pod2 as well. Verify // there is only one pod left. s, rm, rsInformer, podInformer, clientSet := rmSetup(t, true) ns := framework.CreateTestingNamespace("rs-update-selector-to-adopt", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rs := newRS("rs", ns.Name, 1) // let rs's selector only match pod1 rs.Spec.Selector.MatchLabels["uniqueKey"] = "1" rs.Spec.Template.Labels["uniqueKey"] = "1" pod1 := newMatchingPod("pod1", ns.Name) pod1.Labels["uniqueKey"] = "1" pod2 := newMatchingPod("pod2", ns.Name) pod2.Labels["uniqueKey"] = "2" createRSsPods(t, clientSet, []*v1beta1.ReplicaSet{rs}, []*v1.Pod{pod1, pod2}, ns.Name) stopCh := make(chan struct{}) go rsInformer.Run(stopCh) go podInformer.Run(stopCh) go rm.Run(5, stopCh) waitRSStable(t, clientSet, rs, ns.Name) // change the rs's selector to match both pods patch := `{"spec":{"selector":{"matchLabels": {"uniqueKey":null}}}}` rsClient := clientSet.Extensions().ReplicaSets(ns.Name) rs, err := rsClient.Patch(rs.Name, api.StrategicMergePatchType, []byte(patch)) if err != nil { t.Fatalf("Failed to patch replica set: %v", err) } t.Logf("patched rs = %#v", rs) // wait for the rs select both pods and delete one of them if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { return verifyRemainingObjects(t, clientSet, ns.Name, 1, 1) }); err != nil { t.Fatal(err) } close(stopCh) }
func TestUnschedulableNodes(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("unschedulable-nodes", s, t) defer framework.DeleteTestingNamespace(ns, s, t) clientSet := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}) schedulerConfigFactory := factory.NewConfigFactory(clientSet, api.DefaultSchedulerName, api.DefaultHardPodAffinitySymmetricWeight, api.DefaultFailureDomains) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { t.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: api.DefaultSchedulerName}) eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: clientSet.Core().Events(ns.Name)}) scheduler.New(schedulerConfig).Run() defer close(schedulerConfig.StopEverything) DoTestUnschedulableNodes(t, clientSet, ns, schedulerConfigFactory.NodeLister.Store) }
func TestUpdateSelectorToAdopt(t *testing.T) { // We have pod1, pod2 and rc. rc.spec.replicas=1. At first rc.Selector // matches pod1 only; change the selector to match pod2 as well. Verify // there is only one pod left. stopCh := make(chan struct{}) s, rm, _, clientSet := rmSetup(t, stopCh, true) ns := framework.CreateTestingNamespace("update-selector-to-adopt", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rc := newRC("rc", ns.Name, 1) // let rc's selector only match pod1 rc.Spec.Selector["uniqueKey"] = "1" rc.Spec.Template.Labels["uniqueKey"] = "1" pod1 := newMatchingPod("pod1", ns.Name) pod1.Labels["uniqueKey"] = "1" pod2 := newMatchingPod("pod2", ns.Name) pod2.Labels["uniqueKey"] = "2" createRCsPods(t, clientSet, []*v1.ReplicationController{rc}, []*v1.Pod{pod1, pod2}, ns.Name) go rm.Run(5, stopCh) waitRCStable(t, clientSet, rc, ns.Name) // change the rc's selector to match both pods patch := `{"spec":{"selector":{"uniqueKey":null}}}` rcClient := clientSet.Core().ReplicationControllers(ns.Name) rc, err := rcClient.Patch(rc.Name, types.StrategicMergePatchType, []byte(patch)) if err != nil { t.Fatalf("Failed to patch replication controller: %v", err) } t.Logf("patched rc = %#v", rc) // wait for the rc select both pods and delete one of them if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { return verifyRemainingObjects(t, clientSet, ns.Name, 1, 1) }); err != nil { t.Fatal(err) } close(stopCh) }
// TestBobIsForbidden tests that a user who is known to // the authentication system but not authorized to do any actions // should receive "Forbidden". func TestBobIsForbidden(t *testing.T) { // This file has alice and bob in it. masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.Authenticator = getTestTokenAuth() masterConfig.Authorizer = allowAliceAuthorizer{} _, s := framework.RunAMaster(masterConfig) defer s.Close() ns := framework.CreateTestingNamespace("auth-bob-forbidden", s, t) defer framework.DeleteTestingNamespace(ns, s, t) transport := http.DefaultTransport for _, r := range getTestRequests(ns.Name) { token := BobToken bodyBytes := bytes.NewReader([]byte(r.body)) req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) func() { resp, err := transport.RoundTrip(req) defer resp.Body.Close() if err != nil { t.Logf("case %v", r) t.Fatalf("unexpected error: %v", err) } // Expect all of bob's actions to return Forbidden if resp.StatusCode != http.StatusForbidden { t.Logf("case %v", r) t.Errorf("Expected not status Forbidden, but got %s", resp.Status) } }() } }
// This test will verify scheduler can work well regardless of whether kubelet is allocatable aware or not. func TestAllocatable(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() ns := framework.CreateTestingNamespace("allocatable", s, t) defer framework.DeleteTestingNamespace(ns, s, t) // 1. create and start default-scheduler clientSet := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}) // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (Nodes). defer clientSet.Core().Nodes().DeleteCollection(nil, api.ListOptions{}) schedulerConfigFactory := factory.NewConfigFactory(clientSet, api.DefaultSchedulerName, api.DefaultHardPodAffinitySymmetricWeight, api.DefaultFailureDomains) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { t.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: api.DefaultSchedulerName}) eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: clientSet.Core().Events(ns.Name)}) scheduler.New(schedulerConfig).Run() // default-scheduler will be stopped later defer close(schedulerConfig.StopEverything) // 2. create a node without allocatable awareness node := &api.Node{ ObjectMeta: api.ObjectMeta{Name: "node-allocatable-scheduler-test-node"}, Spec: api.NodeSpec{Unschedulable: false}, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), api.ResourceCPU: *resource.NewMilliQuantity(30, resource.DecimalSI), api.ResourceMemory: *resource.NewQuantity(30, resource.BinarySI), }, }, } allocNode, err := clientSet.Core().Nodes().Create(node) if err != nil { t.Fatalf("Failed to create node: %v", err) } // 3. create resource pod which requires less than Capacity podResource := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "pod-test-allocatable"}, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "container", Image: e2e.GetPauseImageName(clientSet), Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceCPU: *resource.NewMilliQuantity(20, resource.DecimalSI), api.ResourceMemory: *resource.NewQuantity(20, resource.BinarySI), }, }, }, }, }, } testAllocPod, err := clientSet.Core().Pods(ns.Name).Create(podResource) if err != nil { t.Fatalf("Test allocatable unawareness failed to create pod: %v", err) } // 4. Test: this test pod should be scheduled since api-server will use Capacity as Allocatable err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testAllocPod.Namespace, testAllocPod.Name)) if err != nil { t.Errorf("Test allocatable unawareness: %s Pod not scheduled: %v", testAllocPod.Name, err) } else { t.Logf("Test allocatable unawareness: %s Pod scheduled", testAllocPod.Name) } // 5. Change the node status to allocatable aware, note that Allocatable is less than Pod's requirement allocNode.Status = api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), api.ResourceCPU: *resource.NewMilliQuantity(30, resource.DecimalSI), api.ResourceMemory: *resource.NewQuantity(30, resource.BinarySI), }, Allocatable: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), api.ResourceCPU: *resource.NewMilliQuantity(10, resource.DecimalSI), api.ResourceMemory: *resource.NewQuantity(10, resource.BinarySI), }, } if _, err := clientSet.Core().Nodes().UpdateStatus(allocNode); err != nil { t.Fatalf("Failed to update node with Status.Allocatable: %v", err) } if err := clientSet.Core().Pods(ns.Name).Delete(podResource.Name, &api.DeleteOptions{}); err != nil { t.Fatalf("Failed to remove first resource pod: %v", err) } // 6. Make another pod with different name, same resource request podResource.ObjectMeta.Name = "pod-test-allocatable2" testAllocPod2, err := clientSet.Core().Pods(ns.Name).Create(podResource) if err != nil { t.Fatalf("Test allocatable awareness failed to create pod: %v", err) } // 7. Test: this test pod should not be scheduled since it request more than Allocatable err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testAllocPod2.Namespace, testAllocPod2.Name)) if err == nil { t.Errorf("Test allocatable awareness: %s Pod got scheduled unexpectly, %v", testAllocPod2.Name, err) } else { t.Logf("Test allocatable awareness: %s Pod not scheduled as expected", testAllocPod2.Name) } }
func TestMultiScheduler(t *testing.T) { _, s := framework.RunAMaster(nil) // TODO: Uncomment when fix #19254 // This seems to be a different issue - it still doesn't work. // defer s.Close() ns := framework.CreateTestingNamespace("multi-scheduler", s, t) defer framework.DeleteTestingNamespace(ns, s, t) /* This integration tests the multi-scheduler feature in the following way: 1. create a default scheduler 2. create a node 3. create 3 pods: testPodNoAnnotation, testPodWithAnnotationFitsDefault and testPodWithAnnotationFitsFoo - note: the first two should be picked and scheduled by default scheduler while the last one should be picked by scheduler of name "foo-scheduler" which does not exist yet. 4. **check point-1**: - testPodNoAnnotation, testPodWithAnnotationFitsDefault should be scheduled - testPodWithAnnotationFitsFoo should NOT be scheduled 5. create a scheduler with name "foo-scheduler" 6. **check point-2**: - testPodWithAnnotationFitsFoo should be scheduled 7. stop default scheduler 8. create 2 pods: testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 - note: these two pods belong to default scheduler which no longer exists 9. **check point-3**: - testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 shoule NOT be scheduled */ // 1. create and start default-scheduler clientSet := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}) // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (Nodes). defer clientSet.Core().Nodes().DeleteCollection(nil, api.ListOptions{}) schedulerConfigFactory := factory.NewConfigFactory(clientSet, api.DefaultSchedulerName, api.DefaultHardPodAffinitySymmetricWeight, api.DefaultFailureDomains) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { t.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: api.DefaultSchedulerName}) eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: clientSet.Core().Events(ns.Name)}) scheduler.New(schedulerConfig).Run() // default-scheduler will be stopped later // 2. create a node node := &api.Node{ ObjectMeta: api.ObjectMeta{Name: "node-multi-scheduler-test-node"}, Spec: api.NodeSpec{Unschedulable: false}, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, }, } clientSet.Core().Nodes().Create(node) // 3. create 3 pods for testing podWithNoAnnotation := createPod(clientSet, "pod-with-no-annotation", nil) testPodNoAnnotation, err := clientSet.Core().Pods(ns.Name).Create(podWithNoAnnotation) if err != nil { t.Fatalf("Failed to create pod: %v", err) } schedulerAnnotationFitsDefault := map[string]string{"scheduler.alpha.kubernetes.io/name": "default-scheduler"} podWithAnnotationFitsDefault := createPod(clientSet, "pod-with-annotation-fits-default", schedulerAnnotationFitsDefault) testPodWithAnnotationFitsDefault, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsDefault) if err != nil { t.Fatalf("Failed to create pod: %v", err) } schedulerAnnotationFitsFoo := map[string]string{"scheduler.alpha.kubernetes.io/name": "foo-scheduler"} podWithAnnotationFitsFoo := createPod(clientSet, "pod-with-annotation-fits-foo", schedulerAnnotationFitsFoo) testPodWithAnnotationFitsFoo, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsFoo) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // 4. **check point-1**: // - testPodNoAnnotation, testPodWithAnnotationFitsDefault should be scheduled // - testPodWithAnnotationFitsFoo should NOT be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodNoAnnotation.Namespace, testPodNoAnnotation.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled: %v", testPodNoAnnotation.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodNoAnnotation.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsDefault.Namespace, testPodWithAnnotationFitsDefault.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled: %v", testPodWithAnnotationFitsDefault.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsDefault.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsFoo.Namespace, testPodWithAnnotationFitsFoo.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodWithAnnotationFitsFoo.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod not scheduled", testPodWithAnnotationFitsFoo.Name) } // 5. create and start a scheduler with name "foo-scheduler" clientSet2 := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}}) schedulerConfigFactory2 := factory.NewConfigFactory(clientSet2, "foo-scheduler", api.DefaultHardPodAffinitySymmetricWeight, api.DefaultFailureDomains) schedulerConfig2, err := schedulerConfigFactory2.Create() if err != nil { t.Errorf("Couldn't create scheduler config: %v", err) } eventBroadcaster2 := record.NewBroadcaster() schedulerConfig2.Recorder = eventBroadcaster2.NewRecorder(api.EventSource{Component: "foo-scheduler"}) eventBroadcaster2.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: clientSet2.Core().Events(ns.Name)}) scheduler.New(schedulerConfig2).Run() defer close(schedulerConfig2.StopEverything) // 6. **check point-2**: // - testPodWithAnnotationFitsFoo should be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsFoo.Namespace, testPodWithAnnotationFitsFoo.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled, %v", testPodWithAnnotationFitsFoo.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsFoo.Name) } // 7. delete the pods that were scheduled by the default scheduler, and stop the default scheduler err = clientSet.Core().Pods(ns.Name).Delete(testPodNoAnnotation.Name, api.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } err = clientSet.Core().Pods(ns.Name).Delete(testPodWithAnnotationFitsDefault.Name, api.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } // The rest of this test assumes that closing StopEverything will cause the // scheduler thread to stop immediately. It won't, and in fact it will often // schedule 1 more pod before finally exiting. Comment out until we fix that. // // See https://github.com/kubernetes/kubernetes/issues/23715 for more details. /* close(schedulerConfig.StopEverything) // 8. create 2 pods: testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 // - note: these two pods belong to default scheduler which no longer exists podWithNoAnnotation2 := createPod("pod-with-no-annotation2", nil) podWithAnnotationFitsDefault2 := createPod("pod-with-annotation-fits-default2", schedulerAnnotationFitsDefault) testPodNoAnnotation2, err := clientSet.Core().Pods(ns.Name).Create(podWithNoAnnotation2) if err != nil { t.Fatalf("Failed to create pod: %v", err) } testPodWithAnnotationFitsDefault2, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsDefault2) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // 9. **check point-3**: // - testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 shoule NOT be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodNoAnnotation2.Namespace, testPodNoAnnotation2.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodNoAnnotation2.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod not scheduled", testPodNoAnnotation2.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsDefault2.Namespace, testPodWithAnnotationFitsDefault2.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodWithAnnotationFitsDefault2.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsDefault2.Name) } */ }
func TestMultiWatch(t *testing.T) { // Disable this test as long as it demonstrates a problem. // TODO: Reenable this test when we get #6059 resolved. return const watcherCount = 50 rt.GOMAXPROCS(watcherCount) _, s := framework.RunAMaster(t) defer s.Close() ns := framework.CreateTestingNamespace("multi-watch", s, t) defer framework.DeleteTestingNamespace(ns, s, t) client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) dummyEvent := func(i int) *api.Event { name := fmt.Sprintf("unrelated-%v", i) return &api.Event{ ObjectMeta: api.ObjectMeta{ Name: fmt.Sprintf("%v.%x", name, time.Now().UnixNano()), Namespace: ns.Name, }, InvolvedObject: api.ObjectReference{ Name: name, Namespace: ns.Name, }, Reason: fmt.Sprintf("unrelated change %v", i), } } type timePair struct { t time.Time name string } receivedTimes := make(chan timePair, watcherCount*2) watchesStarted := sync.WaitGroup{} // make a bunch of pods and watch them for i := 0; i < watcherCount; i++ { watchesStarted.Add(1) name := fmt.Sprintf("multi-watch-%v", i) got, err := client.Pods(ns.Name).Create(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels.Set{"watchlabel": name}, }, Spec: api.PodSpec{ Containers: []api.Container{{ Name: "pause", Image: e2e.GetPauseImageName(client), }}, }, }) if err != nil { t.Fatalf("Couldn't make %v: %v", name, err) } go func(name, rv string) { options := api.ListOptions{ LabelSelector: labels.Set{"watchlabel": name}.AsSelector(), ResourceVersion: rv, } w, err := client.Pods(ns.Name).Watch(options) if err != nil { panic(fmt.Sprintf("watch error for %v: %v", name, err)) } defer w.Stop() watchesStarted.Done() e, ok := <-w.ResultChan() // should get the update (that we'll do below) if !ok { panic(fmt.Sprintf("%v ended early?", name)) } if e.Type != watch.Modified { panic(fmt.Sprintf("Got unexpected watch notification:\n%v: %+v %+v", name, e, e.Object)) } receivedTimes <- timePair{time.Now(), name} }(name, got.ObjectMeta.ResourceVersion) } log.Printf("%v: %v pods made and watchers started", time.Now(), watcherCount) // wait for watches to start before we start spamming the system with // objects below, otherwise we'll hit the watch window restriction. watchesStarted.Wait() const ( useEventsAsUnrelatedType = false usePodsAsUnrelatedType = true ) // make a bunch of unrelated changes in parallel if useEventsAsUnrelatedType { const unrelatedCount = 3000 var wg sync.WaitGroup defer wg.Wait() changeToMake := make(chan int, unrelatedCount*2) changeMade := make(chan int, unrelatedCount*2) go func() { for i := 0; i < unrelatedCount; i++ { changeToMake <- i } close(changeToMake) }() for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() for { i, ok := <-changeToMake if !ok { return } if _, err := client.Events(ns.Name).Create(dummyEvent(i)); err != nil { panic(fmt.Sprintf("couldn't make an event: %v", err)) } changeMade <- i } }() } for i := 0; i < 2000; i++ { <-changeMade if (i+1)%50 == 0 { log.Printf("%v: %v unrelated changes made", time.Now(), i+1) } } } if usePodsAsUnrelatedType { const unrelatedCount = 3000 var wg sync.WaitGroup defer wg.Wait() changeToMake := make(chan int, unrelatedCount*2) changeMade := make(chan int, unrelatedCount*2) go func() { for i := 0; i < unrelatedCount; i++ { changeToMake <- i } close(changeToMake) }() for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() for { i, ok := <-changeToMake if !ok { return } name := fmt.Sprintf("unrelated-%v", i) _, err := client.Pods(ns.Name).Create(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PodSpec{ Containers: []api.Container{{ Name: "nothing", Image: e2e.GetPauseImageName(client), }}, }, }) if err != nil { panic(fmt.Sprintf("couldn't make unrelated pod: %v", err)) } changeMade <- i } }() } for i := 0; i < 2000; i++ { <-changeMade if (i+1)%50 == 0 { log.Printf("%v: %v unrelated changes made", time.Now(), i+1) } } } // Now we still have changes being made in parallel, but at least 1000 have been made. // Make some updates to send down the watches. sentTimes := make(chan timePair, watcherCount*2) for i := 0; i < watcherCount; i++ { go func(i int) { name := fmt.Sprintf("multi-watch-%v", i) pod, err := client.Pods(ns.Name).Get(name) if err != nil { panic(fmt.Sprintf("Couldn't get %v: %v", name, err)) } pod.Spec.Containers[0].Image = e2e.GetPauseImageName(client) sentTimes <- timePair{time.Now(), name} if _, err := client.Pods(ns.Name).Update(pod); err != nil { panic(fmt.Sprintf("Couldn't make %v: %v", name, err)) } }(i) } sent := map[string]time.Time{} for i := 0; i < watcherCount; i++ { tp := <-sentTimes sent[tp.name] = tp.t } log.Printf("all changes made") dur := map[string]time.Duration{} for i := 0; i < watcherCount; i++ { tp := <-receivedTimes delta := tp.t.Sub(sent[tp.name]) dur[tp.name] = delta log.Printf("%v: %v", tp.name, delta) } log.Printf("all watches ended") t.Errorf("durations: %v", dur) }
func TestSingleWatch(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() ns := framework.CreateTestingNamespace("single-watch", s, t) defer framework.DeleteTestingNamespace(ns, s, t) client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) mkEvent := func(i int) *api.Event { name := fmt.Sprintf("event-%v", i) return &api.Event{ ObjectMeta: api.ObjectMeta{ Namespace: ns.Name, Name: name, }, InvolvedObject: api.ObjectReference{ Namespace: ns.Name, Name: name, }, Reason: fmt.Sprintf("event %v", i), } } rv1 := "" for i := 0; i < 10; i++ { event := mkEvent(i) got, err := client.Events(ns.Name).Create(event) if err != nil { t.Fatalf("Failed creating event %#q: %v", event, err) } if rv1 == "" { rv1 = got.ResourceVersion if rv1 == "" { t.Fatal("did not get a resource version.") } } t.Logf("Created event %#v", got.ObjectMeta) } w, err := client.Get(). Prefix("watch"). Namespace(ns.Name). Resource("events"). Name("event-9"). Param("resourceVersion", rv1). Watch() if err != nil { t.Fatalf("Failed watch: %v", err) } defer w.Stop() select { case <-time.After(wait.ForeverTestTimeout): t.Fatalf("watch took longer than %s", wait.ForeverTestTimeout.String()) case got, ok := <-w.ResultChan(): if !ok { t.Fatal("Watch channel closed unexpectedly.") } // We expect to see an ADD of event-9 and only event-9. (This // catches a bug where all the events would have been sent down // the channel.) if e, a := watch.Added, got.Type; e != a { t.Errorf("Wanted %v, got %v", e, a) } switch o := got.Object.(type) { case *api.Event: if e, a := "event-9", o.Name; e != a { t.Errorf("Wanted %v, got %v", e, a) } default: t.Fatalf("Unexpected watch event containing object %#q", got) } } }
func TestClient(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) ns := framework.CreateTestingNamespace("client", s, t) defer framework.DeleteTestingNamespace(ns, s, t) info, err := client.Discovery().ServerVersion() if err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := version.Get(), *info; !reflect.DeepEqual(e, a) { t.Errorf("expected %#v, got %#v", e, a) } pods, err := client.Pods(ns.Name).List(api.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(pods.Items) != 0 { t.Errorf("expected no pods, got %#v", pods) } // get a validation error pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ GenerateName: "test", Namespace: ns.Name, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "test", }, }, }, } got, err := client.Pods(ns.Name).Create(pod) if err == nil { t.Fatalf("unexpected non-error: %v", got) } // get a created pod pod.Spec.Containers[0].Image = "an-image" got, err = client.Pods(ns.Name).Create(pod) if err != nil { t.Fatalf("unexpected error: %v", err) } if got.Name == "" { t.Errorf("unexpected empty pod Name %v", got) } // pod is shown, but not scheduled pods, err = client.Pods(ns.Name).List(api.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(pods.Items) != 1 { t.Errorf("expected one pod, got %#v", pods) } actual := pods.Items[0] if actual.Name != got.Name { t.Errorf("expected pod %#v, got %#v", got, actual) } if actual.Spec.NodeName != "" { t.Errorf("expected pod to be unscheduled, got %#v", actual) } }
func TestPatchWithCreateOnUpdate(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() c := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) ns := framework.CreateTestingNamespace("patch-with-create", s, t) defer framework.DeleteTestingNamespace(ns, s, t) endpointTemplate := &api.Endpoints{ ObjectMeta: api.ObjectMeta{ Name: "patchendpoint", Namespace: ns.Name, }, Subsets: []api.EndpointSubset{ { Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{{Port: 80, Protocol: api.ProtocolTCP}}, }, }, } patchEndpoint := func(json []byte) (runtime.Object, error) { return c.Patch(api.MergePatchType).Resource("endpoints").Namespace(ns.Name).Name("patchendpoint").Body(json).Do().Get() } // Make sure patch doesn't get to CreateOnUpdate { endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if obj, err := patchEndpoint(endpointJSON); !apierrors.IsNotFound(err) { t.Errorf("Expected notfound creating from patch, got error=%v and object: %#v", err, obj) } } // Create the endpoint (endpoints set AllowCreateOnUpdate=true) to get a UID and resource version createdEndpoint, err := c.Endpoints(ns.Name).Update(endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint: %v", err) } // Make sure identity patch is accepted { endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), createdEndpoint) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); err != nil { t.Errorf("Failed patching endpoint: %v", err) } } // Make sure patch complains about a mismatched resourceVersion { endpointTemplate.Name = "" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "1" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsConflict(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch complains about mutating the UID { endpointTemplate.Name = "" endpointTemplate.UID = "abc" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsInvalid(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch complains about a mismatched name { endpointTemplate.Name = "changedname" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsBadRequest(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch containing originally submitted JSON is accepted { endpointTemplate.Name = "" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); err != nil { t.Errorf("Failed patching endpoint: %v", err) } } }
func TestPatch(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() c := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) ns := framework.CreateTestingNamespace("patch", s, t) defer framework.DeleteTestingNamespace(ns, s, t) name := "patchpod" resource := "pods" podBody := api.Pod{ TypeMeta: unversioned.TypeMeta{ APIVersion: c.APIVersion().String(), }, ObjectMeta: api.ObjectMeta{ Name: name, Namespace: ns.Name, Labels: map[string]string{}, }, Spec: api.PodSpec{ Containers: []api.Container{ {Name: "name", Image: "image"}, }, }, } pods := c.Pods(ns.Name) pod, err := pods.Create(&podBody) if err != nil { t.Fatalf("Failed creating patchpods: %v", err) } patchBodies := map[unversioned.GroupVersion]map[api.PatchType]struct { AddLabelBody []byte RemoveLabelBody []byte RemoveAllLabelsBody []byte }{ v1.SchemeGroupVersion: { api.JSONPatchType: { []byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`), []byte(`[{"op":"remove","path":"/metadata/labels/foo"}]`), []byte(`[{"op":"remove","path":"/metadata/labels"}]`), }, api.MergePatchType: { []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`), []byte(`{"metadata":{"labels":{"foo":null}}}`), []byte(`{"metadata":{"labels":null}}`), }, api.StrategicMergePatchType: { []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`), []byte(`{"metadata":{"labels":{"foo":null}}}`), []byte(`{"metadata":{"labels":{"$patch":"replace"}}}`), }, }, } pb := patchBodies[c.APIVersion()] execPatch := func(pt api.PatchType, body []byte) error { return c.Patch(pt). Resource(resource). Namespace(ns.Name). Name(name). Body(body). Do(). Error() } for k, v := range pb { // add label err := execPatch(k, v.AddLabelBody) if err != nil { t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err) } pod, err = pods.Get(name) if err != nil { t.Fatalf("Failed getting patchpod: %v", err) } if len(pod.Labels) != 2 || pod.Labels["foo"] != "bar" || pod.Labels["baz"] != "qux" { t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels) } // remove one label err = execPatch(k, v.RemoveLabelBody) if err != nil { t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err) } pod, err = pods.Get(name) if err != nil { t.Fatalf("Failed getting patchpod: %v", err) } if len(pod.Labels) != 1 || pod.Labels["baz"] != "qux" { t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels) } // remove all labels err = execPatch(k, v.RemoveAllLabelsBody) if err != nil { t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err) } pod, err = pods.Get(name) if err != nil { t.Fatalf("Failed getting patchpod: %v", err) } if pod.Labels != nil { t.Errorf("Failed remove all labels from patchpod with patch type %s: %v", k, pod.Labels) } } }
func TestAtomicPut(t *testing.T) { _, s := framework.RunAMaster(t) defer s.Close() c := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}) ns := framework.CreateTestingNamespace("atomic-put", s, t) defer framework.DeleteTestingNamespace(ns, s, t) rcBody := api.ReplicationController{ TypeMeta: unversioned.TypeMeta{ APIVersion: c.APIVersion().String(), }, ObjectMeta: api.ObjectMeta{ Name: "atomicrc", Namespace: ns.Name, Labels: map[string]string{ "name": "atomicrc", }, }, Spec: api.ReplicationControllerSpec{ Replicas: 0, Selector: map[string]string{ "foo": "bar", }, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, Spec: api.PodSpec{ Containers: []api.Container{ {Name: "name", Image: "image"}, }, }, }, }, } rcs := c.ReplicationControllers(ns.Name) rc, err := rcs.Create(&rcBody) if err != nil { t.Fatalf("Failed creating atomicRC: %v", err) } testLabels := labels.Set{ "foo": "bar", } for i := 0; i < 5; i++ { // a: z, b: y, etc... testLabels[string([]byte{byte('a' + i)})] = string([]byte{byte('z' - i)}) } var wg sync.WaitGroup wg.Add(len(testLabels)) for label, value := range testLabels { go func(l, v string) { defer wg.Done() for { tmpRC, err := rcs.Get(rc.Name) if err != nil { t.Errorf("Error getting atomicRC: %v", err) continue } if tmpRC.Spec.Selector == nil { tmpRC.Spec.Selector = map[string]string{l: v} tmpRC.Spec.Template.Labels = map[string]string{l: v} } else { tmpRC.Spec.Selector[l] = v tmpRC.Spec.Template.Labels[l] = v } tmpRC, err = rcs.Update(tmpRC) if err != nil { if apierrors.IsConflict(err) { // This is what we expect. continue } t.Errorf("Unexpected error putting atomicRC: %v", err) continue } return } }(label, value) } wg.Wait() rc, err = rcs.Get(rc.Name) if err != nil { t.Fatalf("Failed getting atomicRC after writers are complete: %v", err) } if !reflect.DeepEqual(testLabels, labels.Set(rc.Spec.Selector)) { t.Errorf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, rc.Spec.Selector) } }