// StartPods check for numPods in TestNS. If they exist, it no-ops, otherwise it starts up // a temp rc, scales it to match numPods, then deletes the rc leaving behind the pods. func StartPods(numPods int, host string, restClient *client.Client) error { start := time.Now() defer func() { glog.Infof("StartPods took %v with numPods %d", time.Since(start), numPods) }() hostField := fields.OneTermEqualSelector(client.PodHost, host) pods, err := restClient.Pods(TestNS).List(labels.Everything(), hostField) if err != nil || len(pods.Items) == numPods { return err } glog.Infof("Found %d pods that match host %v, require %d", len(pods.Items), hostField, numPods) // For the sake of simplicity, assume all pods in TestNS have selectors matching TestRCManifest. controller := RCFromManifest(TestRCManifest) // Make the rc unique to the given host. controller.Spec.Replicas = numPods controller.Spec.Template.Spec.NodeName = host controller.Name = controller.Name + host controller.Spec.Selector["host"] = host controller.Spec.Template.Labels["host"] = host if rc, err := StartRC(controller, restClient); err != nil { return err } else { // Delete the rc, otherwise when we restart master components for the next benchmark // the rc controller will race with the pods controller in the rc manager. return restClient.ReplicationControllers(TestNS).Delete(rc.Name) } }
// testHostIP tests that a pod gets a host IP func testHostIP(c *client.Client, pod *api.Pod) { ns := "e2e-test-" + string(util.NewUUID()) _, err := createNamespaceIfDoesNotExist(c, ns) expectNoError(err, fmt.Sprintf("creating namespace %s", ns)) podClient := c.Pods(ns) By("creating pod") defer podClient.Delete(pod.Name, nil) _, err = podClient.Create(pod) if err != nil { Fail(fmt.Sprintf("Failed to create pod: %v", err)) } By("ensuring that pod is running and has a hostIP") // Wait for the pods to enter the running state. Waiting loops until the pods // are running so non-running pods cause a timeout for this test. err = waitForPodRunningInNamespace(c, pod.Name, ns) Expect(err).NotTo(HaveOccurred()) // Try to make sure we get a hostIP for each pod. hostIPTimeout := 2 * time.Minute t := time.Now() for { p, err := podClient.Get(pod.Name) Expect(err).NotTo(HaveOccurred()) if p.Status.HostIP != "" { Logf("Pod %s has hostIP: %s", p.Name, p.Status.HostIP) break } if time.Since(t) >= hostIPTimeout { Failf("Gave up waiting for hostIP of pod %s after %v seconds", p.Name, time.Since(t).Seconds()) } Logf("Retrying to get the hostIP of pod %s", p.Name) time.Sleep(5 * time.Second) } }
func verifyExpectedRcsExistAndGetExpectedPods(c *client.Client) ([]string, error) { expectedPods := []string{} // Iterate over the labels that identify the replication controllers that we // want to check. The rcLabels contains the value values for the k8s-app key // that identify the replication controllers that we want to check. Using a label // rather than an explicit name is preferred because the names will typically have // a version suffix e.g. heapster-monitoring-v1 and this will change after a rolling // update e.g. to heapster-monitoring-v2. By using a label query we can check for the // situaiton when a heapster-monitoring-v1 and heapster-monitoring-v2 replication controller // is running (which would be an error except during a rolling update). for _, rcLabel := range rcLabels { rcList, err := c.ReplicationControllers(api.NamespaceDefault).List(labels.Set{"k8s-app": rcLabel}.AsSelector()) if err != nil { return nil, err } if len(rcList.Items) != 1 { return nil, fmt.Errorf("expected to find one replica for RC with label %s but got %d", rcLabel, len(rcList.Items)) } for _, rc := range rcList.Items { podList, err := c.Pods(api.NamespaceDefault).List(labels.Set(rc.Spec.Selector).AsSelector(), fields.Everything()) if err != nil { return nil, err } for _, pod := range podList.Items { expectedPods = append(expectedPods, string(pod.UID)) } } } return expectedPods, nil }
func runSchedulerNoPhantomPodsTest(client *client.Client) { pod := &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{ { Name: "c1", Image: "qingyuan/pause", Ports: []api.ContainerPort{ {ContainerPort: 1234, HostPort: 9999}, }, ImagePullPolicy: api.PullIfNotPresent, }, }, }, } // Assuming we only have two kublets, the third pod here won't schedule // if the scheduler doesn't correctly handle the delete for the second // pod. pod.ObjectMeta.Name = "phantom.foo" foo, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*30, podRunning(client, foo.Namespace, foo.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } pod.ObjectMeta.Name = "phantom.bar" bar, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*30, podRunning(client, bar.Namespace, bar.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } // Delete a pod to free up room. glog.Infof("Deleting pod %v", bar.Name) err = client.Pods(api.NamespaceDefault).Delete(bar.Name, nil) if err != nil { glog.Fatalf("FAILED: couldn't delete pod %q: %v", bar.Name, err) } pod.ObjectMeta.Name = "phantom.baz" baz, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*60, podRunning(client, baz.Namespace, baz.Name)); err != nil { glog.Fatalf("FAILED: (Scheduler probably didn't process deletion of 'phantom.bar') Pod never started running: %v", err) } glog.Info("Scheduler doesn't make phantom pods: test passed.") }
func translatePodNameToIpOrFail(c *client.Client, ns string, expectedEndpoints map[string][]int) map[string][]int { portsByIp := make(map[string][]int) for name, portList := range expectedEndpoints { pod, err := c.Pods(ns).Get(name) if err != nil { Failf("failed to get pod %s, that's pretty weird. validation failed: %s", name, err) } portsByIp[pod.Status.PodIP] = portList By(fmt.Sprintf("")) } By(fmt.Sprintf("successfully translated pod names to ips: %v -> %v on namespace %s", expectedEndpoints, portsByIp, ns)) return portsByIp }
func doServiceAccountAPIRequests(t *testing.T, c *client.Client, ns string, authenticated bool, canRead bool, canWrite bool) { testSecret := &api.Secret{ ObjectMeta: api.ObjectMeta{Name: "testSecret"}, Data: map[string][]byte{"test": []byte("data")}, } readOps := []testOperation{ func() error { _, err := c.Secrets(ns).List(labels.Everything(), fields.Everything()); return err }, func() error { _, err := c.Pods(ns).List(labels.Everything(), fields.Everything()); return err }, } writeOps := []testOperation{ func() error { _, err := c.Secrets(ns).Create(testSecret); return err }, func() error { return c.Secrets(ns).Delete(testSecret.Name) }, } for _, op := range readOps { err := op() unauthorizedError := errors.IsUnauthorized(err) forbiddenError := errors.IsForbidden(err) switch { case !authenticated && !unauthorizedError: t.Fatalf("expected unauthorized error, got %v", err) case authenticated && unauthorizedError: t.Fatalf("unexpected unauthorized error: %v", err) case authenticated && canRead && forbiddenError: t.Fatalf("unexpected forbidden error: %v", err) case authenticated && !canRead && !forbiddenError: t.Fatalf("expected forbidden error, got: %v", err) } } for _, op := range writeOps { err := op() unauthorizedError := errors.IsUnauthorized(err) forbiddenError := errors.IsForbidden(err) switch { case !authenticated && !unauthorizedError: t.Fatalf("expected unauthorized error, got %v", err) case authenticated && unauthorizedError: t.Fatalf("unexpected unauthorized error: %v", err) case authenticated && canWrite && forbiddenError: t.Fatalf("unexpected forbidden error: %v", err) case authenticated && !canWrite && !forbiddenError: t.Fatalf("expected forbidden error, got: %v", err) } } }
func podScheduled(c *client.Client, podNamespace, podName string) wait.ConditionFunc { return func() (bool, error) { pod, err := c.Pods(podNamespace).Get(podName) if errors.IsNotFound(err) { return false, nil } if err != nil { // This could be a connection error so we want to retry. return false, nil } if pod.Spec.NodeName == "" { return false, nil } return true, nil } }
func podRunning(c *client.Client, podNamespace string, podName string) wait.ConditionFunc { return func() (bool, error) { pod, err := c.Pods(podNamespace).Get(podName) if apierrors.IsNotFound(err) { return false, nil } if err != nil { // This could be a connection error so we want to retry, but log the error. glog.Errorf("Error when reading pod %q: %v", podName, err) return false, nil } if pod.Status.Phase != api.PodRunning { return false, nil } return true, nil } }
// Starts a container specified by config.serverImage and exports all // config.serverPorts from it. The returned pod should be used to get the server // IP address and create appropriate VolumeSource. func startVolumeServer(client *client.Client, config VolumeTestConfig) *api.Pod { podClient := client.Pods(config.namespace) portCount := len(config.serverPorts) serverPodPorts := make([]api.ContainerPort, portCount) for i := 0; i < portCount; i++ { portName := fmt.Sprintf("%s-%d", config.prefix, i) serverPodPorts[i] = api.ContainerPort{ Name: portName, ContainerPort: config.serverPorts[i], Protocol: api.ProtocolTCP, } } By(fmt.Sprint("creating ", config.prefix, " server pod")) privileged := new(bool) *privileged = true serverPod := &api.Pod{ TypeMeta: api.TypeMeta{ Kind: "Pod", APIVersion: "v1", }, ObjectMeta: api.ObjectMeta{ Name: config.prefix + "-server", Labels: map[string]string{ "role": config.prefix + "-server", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: config.prefix + "-server", Image: config.serverImage, SecurityContext: &api.SecurityContext{ Privileged: privileged, }, Ports: serverPodPorts, }, }, }, } _, err := podClient.Create(serverPod) expectNoError(err, "Failed to create %s pod: %v", serverPod.Name, err) expectNoError(waitForPodRunningInNamespace(client, serverPod.Name, config.namespace)) By("locating the server pod") pod, err := podClient.Get(serverPod.Name) expectNoError(err, "Cannot locate the server pod %v: %v", serverPod.Name, err) By("sleeping a bit to give the server time to start") time.Sleep(20 * time.Second) return pod }
// Clean both server and client pods. func volumeTestCleanup(client *client.Client, config VolumeTestConfig) { By(fmt.Sprint("cleaning the environment after ", config.prefix)) defer GinkgoRecover() podClient := client.Pods(config.namespace) // ignore all errors, the pods may not be even created podClient.Delete(config.prefix+"-client", nil) podClient.Delete(config.prefix+"-server", nil) }
func addEndpointPodOrFail(c *client.Client, ns, name string, labels map[string]string, containerPorts []api.ContainerPort) { By(fmt.Sprintf("Adding pod %v in namespace %v", name, ns)) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "test", Image: "qingyuan/pause", Ports: containerPorts, }, }, }, } _, err := c.Pods(ns).Create(pod) Expect(err).NotTo(HaveOccurred()) }
func runLivenessTest(c *client.Client, podDescr *api.Pod, expectRestart bool) { ns := "e2e-test-" + string(util.NewUUID()) _, err := createNamespaceIfDoesNotExist(c, ns) expectNoError(err, fmt.Sprintf("creating namespace %s", ns)) By(fmt.Sprintf("Creating pod %s in namespace %s", podDescr.Name, ns)) _, err = c.Pods(ns).Create(podDescr) expectNoError(err, fmt.Sprintf("creating pod %s", podDescr.Name)) // At the end of the test, clean up by removing the pod. defer func() { By("deleting the pod") c.Pods(ns).Delete(podDescr.Name, nil) }() // Wait until the pod is not pending. (Here we need to check for something other than // 'Pending' other than checking for 'Running', since when failures occur, we go to // 'Terminated' which can cause indefinite blocking.) expectNoError(waitForPodNotPending(c, ns, podDescr.Name), fmt.Sprintf("starting pod %s in namespace %s", podDescr.Name, ns)) By(fmt.Sprintf("Started pod %s in namespace %s", podDescr.Name, ns)) // Check the pod's current state and verify that restartCount is present. By("checking the pod's current state and verifying that restartCount is present") pod, err := c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s in namespace %s", podDescr.Name, ns)) initialRestartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount By(fmt.Sprintf("Initial restart count of pod %s is %d", podDescr.Name, initialRestartCount)) // Wait for at most 48 * 5 = 240s = 4 minutes until restartCount is incremented restarts := false for i := 0; i < 48; i++ { // Wait until restartCount is incremented. time.Sleep(5 * time.Second) pod, err = c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s", podDescr.Name)) restartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount By(fmt.Sprintf("Restart count of pod %s in namespace %s is now %d", podDescr.Name, ns, restartCount)) if restartCount > initialRestartCount { By(fmt.Sprintf("Restart count of pod %s in namespace %s increased from %d to %d during the test", podDescr.Name, ns, initialRestartCount, restartCount)) restarts = true break } } if restarts != expectRestart { Fail(fmt.Sprintf("pod %s in namespace %s - expected restarts: %v, found restarts: %v", podDescr.Name, ns, expectRestart, restarts)) } }
// podsOnMinions returns true when all of the selected pods exist on a minion. func podsOnMinions(c *client.Client, podNamespace string, labelSelector labels.Selector) wait.ConditionFunc { // Wait until all pods are running on the node. return func() (bool, error) { pods, err := c.Pods(podNamespace).List(labelSelector, fields.Everything()) if err != nil { glog.Infof("Unable to get pods to list: %v", err) return false, nil } for i := range pods.Items { pod := pods.Items[i] podString := fmt.Sprintf("%q/%q", pod.Namespace, pod.Name) glog.Infof("Check whether pod %q exists on node %q", podString, pod.Spec.NodeName) if len(pod.Spec.NodeName) == 0 { glog.Infof("Pod %q is not bound to a host yet", podString) return false, nil } if pod.Status.Phase != api.PodRunning { return false, nil } } return true, nil } }
func createRunningPod(wg *sync.WaitGroup, c *client.Client, name, ns, image string, labels map[string]string) { defer GinkgoRecover() defer wg.Done() pod := &api.Pod{ TypeMeta: api.TypeMeta{ Kind: "Pod", }, ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: name, Image: image, }, }, }, } _, err := c.Pods(ns).Create(pod) expectNoError(err) expectNoError(waitForPodRunningInNamespace(c, name, ns)) }
err = c.PersistentVolumeClaims(ns).Delete(pvc.Name) Expect(err).NotTo(HaveOccurred()) // allow the recycler a chance to catch up. it has to perform NFS scrub, which can be slow in e2e. waitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 5*time.Second, 300*time.Second) pv, err = c.PersistentVolumes().Get(pv.Name) Expect(err).NotTo(HaveOccurred()) if pv.Spec.ClaimRef != nil { Failf("Expected PersistentVolume to be unbound, but found non-nil ClaimRef: %+v", pv) } // The NFS Server pod we're using contains an index.html file // Verify the file was really scrubbed from the volume podTemplate := makeCheckPod(ns, serverIP) checkpod, err := c.Pods(ns).Create(podTemplate) expectNoError(err, "Failed to create checker pod: %v", err) err = waitForPodSuccessInNamespace(c, checkpod.Name, checkpod.Spec.Containers[0].Name, checkpod.Namespace) Expect(err).NotTo(HaveOccurred()) }) }) func makePersistentVolume(serverIP string) *api.PersistentVolume { return &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ GenerateName: "nfs-", }, Spec: api.PersistentVolumeSpec{ PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle, Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("2Gi"),
func podNotFound(c *client.Client, podNamespace string, podName string) wait.ConditionFunc { return func() (bool, error) { _, err := c.Pods(podNamespace).Get(podName) return apierrors.IsNotFound(err), nil } }
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Events", func() { var c *client.Client BeforeEach(func() { var err error c, err = loadClient() Expect(err).NotTo(HaveOccurred()) }) It("should be sent by qinglets and the scheduler about pods scheduling and running", func() { podClient := c.Pods(api.NamespaceDefault) By("creating the pod") name := "send-events-" + string(util.NewUUID()) value := strconv.Itoa(time.Now().Nanosecond()) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: map[string]string{ "name": "foo", "time": value, }, }, Spec: api.PodSpec{ Containers: []api.Container{ {
// runStaticPodTest is disabled until #6651 is resolved. func runStaticPodTest(c *client.Client, configFilePath string) { var testCases = []struct { desc string fileContents string }{ { desc: "static-pod-from-manifest", fileContents: `version: v1beta2 id: static-pod-from-manifest containers: - name: static-container image: qingyuan/pause`, }, { desc: "static-pod-from-spec", fileContents: `{ "kind": "Pod", "apiVersion": "v1beta3", "metadata": { "name": "static-pod-from-spec" }, "spec": { "containers": [{ "name": "static-container", "image": "qingyuan/pause" }] } }`, }, } for _, testCase := range testCases { func() { desc := testCase.desc manifestFile, err := ioutil.TempFile(configFilePath, "") defer os.Remove(manifestFile.Name()) ioutil.WriteFile(manifestFile.Name(), []byte(testCase.fileContents), 0600) // Wait for the mirror pod to be created. podName := fmt.Sprintf("%s-localhost", desc) namespace := qinglet.NamespaceDefault if err := wait.Poll(time.Second, time.Minute*2, podRunning(c, namespace, podName)); err != nil { if pods, err := c.Pods(namespace).List(labels.Everything(), fields.Everything()); err == nil { for _, pod := range pods.Items { glog.Infof("pod found: %s/%s", namespace, pod.Name) } } glog.Fatalf("%s FAILED: mirror pod has not been created or is not running: %v", desc, err) } // Delete the mirror pod, and wait for it to be recreated. c.Pods(namespace).Delete(podName, nil) if err = wait.Poll(time.Second, time.Minute*1, podRunning(c, namespace, podName)); err != nil { glog.Fatalf("%s FAILED: mirror pod has not been re-created or is not running: %v", desc, err) } // Remove the manifest file, and wait for the mirror pod to be deleted. os.Remove(manifestFile.Name()) if err = wait.Poll(time.Second, time.Minute*1, podNotFound(c, namespace, podName)); err != nil { glog.Fatalf("%s FAILED: mirror pod has not been deleted: %v", desc, err) } }() } }
// DoTestSecrets test secrets for one api version. func DoTestSecrets(t *testing.T, client *client.Client, apiVersion string) { // Make a secret object. ns := "ns" s := api.Secret{ ObjectMeta: api.ObjectMeta{ Name: "secret", Namespace: ns, }, Data: map[string][]byte{ "data": []byte("value1\n"), }, } if _, err := client.Secrets(s.Namespace).Create(&s); err != nil { t.Errorf("unable to create test secret: %v", err) } defer deleteSecretOrErrorf(t, client, s.Namespace, s.Name) // Template for pods that use a secret. pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "XXX", }, Spec: api.PodSpec{ Volumes: []api.Volume{ { Name: "secvol", VolumeSource: api.VolumeSource{ Secret: &api.SecretVolumeSource{ SecretName: "secret", }, }, }, }, Containers: []api.Container{ { Name: "fake-name", Image: "fakeimage", VolumeMounts: []api.VolumeMount{ { Name: "secvol", MountPath: "/fake/path", ReadOnly: true, }, }, }, }, }, } // Create a pod to consume secret. pod.ObjectMeta.Name = "uses-secret" if _, err := client.Pods(ns).Create(pod); err != nil { t.Errorf("Failed to create pod: %v", err) } defer deletePodOrErrorf(t, client, ns, pod.Name) // Create a pod that consumes non-existent secret. pod.ObjectMeta.Name = "uses-non-existent-secret" if _, err := client.Pods(ns).Create(pod); err != nil { t.Errorf("Failed to create pod: %v", err) } defer deletePodOrErrorf(t, client, ns, pod.Name) // This pod may fail to run, but we don't currently prevent this, and this // test can't check whether the qinglet actually pulls the secret. // Verifying contents of the volumes is out of scope for a // apiserver<->qinglet integration test. It is covered by an e2e test. }
func deletePodOrErrorf(t *testing.T, c *client.Client, ns, name string) { if err := c.Pods(ns).Delete(name, nil); err != nil { t.Errorf("unable to delete pod %v: %v", name, err) } }
func runServiceTest(client *client.Client) { pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Labels: map[string]string{ "name": "thisisalonglabel", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "c1", Image: "foo", Ports: []api.ContainerPort{ {ContainerPort: 1234}, }, ImagePullPolicy: api.PullIfNotPresent, }, }, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, Status: api.PodStatus{ PodIP: "1.2.3.4", }, } pod, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*20, podExists(client, pod.Namespace, pod.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } svc1 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service1"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc1, err = client.Services(api.NamespaceDefault).Create(svc1) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc1, err) } // create an identical service in the non-default namespace svc3 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service1"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc3, err = client.Services("other").Create(svc3) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc3, err) } // TODO Reduce the timeouts in this test when endpoints controller is sped up. See #6045. if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc1.Namespace, svc1.Name, 1)); err != nil { glog.Fatalf("FAILED: unexpected endpoints: %v", err) } // A second service with the same port. svc2 := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "service2"}, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "thisisalonglabel", }, Ports: []api.ServicePort{{ Port: 8080, Protocol: "TCP", }}, SessionAffinity: "None", }, } svc2, err = client.Services(api.NamespaceDefault).Create(svc2) if err != nil { glog.Fatalf("Failed to create service: %v, %v", svc2, err) } if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc2.Namespace, svc2.Name, 1)); err != nil { glog.Fatalf("FAILED: unexpected endpoints: %v", err) } if err := wait.Poll(time.Second, time.Second*60, endpointsSet(client, svc3.Namespace, svc3.Name, 0)); err != nil { glog.Fatalf("FAILED: service in other namespace should have no endpoints: %v", err) } svcList, err := client.Services(api.NamespaceAll).List(labels.Everything()) if err != nil { glog.Fatalf("Failed to list services across namespaces: %v", err) } names := util.NewStringSet() for _, svc := range svcList.Items { names.Insert(fmt.Sprintf("%s/%s", svc.Namespace, svc.Name)) } if !names.HasAll("default/qingyuan", "default/service1", "default/service2", "other/service1") { glog.Fatalf("Unexpected service list: %#v", names) } glog.Info("Service test passed.") }
func DoTestUnschedulableNodes(t *testing.T, restClient *client.Client, nodeStore cache.Store) { goodCondition := api.NodeCondition{ Type: api.NodeReady, Status: api.ConditionTrue, Reason: fmt.Sprintf("schedulable condition"), LastHeartbeatTime: util.Time{time.Now()}, } badCondition := api.NodeCondition{ Type: api.NodeReady, Status: api.ConditionUnknown, Reason: fmt.Sprintf("unschedulable condition"), LastHeartbeatTime: util.Time{time.Now()}, } // Create a new schedulable node, since we're first going to apply // the unschedulable condition and verify that pods aren't scheduled. node := &api.Node{ ObjectMeta: api.ObjectMeta{Name: "node-scheduling-test-node"}, Spec: api.NodeSpec{Unschedulable: false}, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.NodeCondition{goodCondition}, }, } nodeKey, err := cache.MetaNamespaceKeyFunc(node) if err != nil { t.Fatalf("Couldn't retrieve key for node %v", node.Name) } // The test does the following for each nodeStateManager in this list: // 1. Create a new node // 2. Apply the makeUnSchedulable function // 3. Create a new pod // 4. Check that the pod doesn't get assigned to the node // 5. Apply the schedulable function // 6. Check that the pod *does* get assigned to the node // 7. Delete the pod and node. nodeModifications := []nodeStateManager{ // Test node.Spec.Unschedulable=true/false { makeUnSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Spec.Unschedulable = true if _, err := c.Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=true: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { // An unschedulable node should get deleted from the store return node == nil }) if err != nil { t.Fatalf("Failed to observe reflected update for setting unschedulable=true: %v", err) } }, makeSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Spec.Unschedulable = false if _, err := c.Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=false: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.Node).Spec.Unschedulable == false }) if err != nil { t.Fatalf("Failed to observe reflected update for setting unschedulable=false: %v", err) } }, }, // Test node.Status.Conditions=ConditionTrue/Unknown { makeUnSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Status = api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.NodeCondition{badCondition}, } if _, err = c.Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with bad status condition: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.Node).Status.Conditions[0].Status == api.ConditionUnknown }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, makeSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Status = api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.NodeCondition{goodCondition}, } if _, err = c.Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with healthy status condition: %v", err) } waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.Node).Status.Conditions[0].Status == api.ConditionTrue }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, }, } for i, mod := range nodeModifications { unSchedNode, err := restClient.Nodes().Create(node) if err != nil { t.Fatalf("Failed to create node: %v", err) } // Apply the unschedulable modification to the node, and wait for the reflection mod.makeUnSchedulable(t, unSchedNode, nodeStore, restClient) // Create the new pod, note that this needs to happen post unschedulable // modification or we have a race in the test. pod := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "node-scheduling-test-pod"}, Spec: api.PodSpec{ Containers: []api.Container{{Name: "container", Image: "qingyuan/pause:go"}}, }, } myPod, err := restClient.Pods(api.NamespaceDefault).Create(pod) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // There are no schedulable nodes - the pod shouldn't be scheduled. err = wait.Poll(time.Second, time.Second*10, podScheduled(restClient, myPod.Namespace, myPod.Name)) if err == nil { t.Errorf("Pod scheduled successfully on unschedulable nodes") } if err != wait.ErrWaitTimeout { t.Errorf("Test %d: failed while trying to confirm the pod does not get scheduled on the node: %v", i, err) } else { t.Logf("Test %d: Pod did not get scheduled on an unschedulable node", i) } // Apply the schedulable modification to the node, and wait for the reflection schedNode, err := restClient.Nodes().Get(unSchedNode.Name) if err != nil { t.Fatalf("Failed to get node: %v", err) } mod.makeSchedulable(t, schedNode, nodeStore, restClient) // Wait until the pod is scheduled. err = wait.Poll(time.Second, time.Second*10, podScheduled(restClient, myPod.Namespace, myPod.Name)) if err != nil { t.Errorf("Test %d: failed to schedule a pod: %v", i, err) } else { t.Logf("Test %d: Pod got scheduled on a schedulable node", i) } err = restClient.Pods(api.NamespaceDefault).Delete(myPod.Name, nil) if err != nil { t.Errorf("Failed to delete pod: %v", err) } err = restClient.Nodes().Delete(schedNode.Name) if err != nil { t.Errorf("Failed to delete node: %v", err) } } }
func testPreStop(c *client.Client, ns string) { // This is the server that will receive the preStop notification podDescr := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "server", }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "server", Image: "qingyuan/nettest:1.3", Ports: []api.ContainerPort{{ContainerPort: 8080}}, }, }, }, } By(fmt.Sprintf("Creating server pod %s in namespace %s", podDescr.Name, ns)) _, err := c.Pods(ns).Create(podDescr) expectNoError(err, fmt.Sprintf("creating pod %s", podDescr.Name)) // At the end of the test, clean up by removing the pod. defer func() { By("Deleting the server pod") c.Pods(ns).Delete(podDescr.Name, nil) }() By("Waiting for pods to come up.") err = waitForPodRunningInNamespace(c, podDescr.Name, ns) expectNoError(err, "waiting for server pod to start") val := "{\"Source\": \"prestop\"}" podOut, err := c.Pods(ns).Get(podDescr.Name) expectNoError(err, "getting pod info") preStopDescr := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "tester", }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "tester", Image: "qingyuan/busybox", Command: []string{"sleep", "600"}, Lifecycle: &api.Lifecycle{ PreStop: &api.Handler{ Exec: &api.ExecAction{ Command: []string{ "wget", "-O-", "--post-data=" + val, fmt.Sprintf("http://%s:8080/write", podOut.Status.PodIP), }, }, }, }, }, }, }, } By(fmt.Sprintf("Creating tester pod %s in namespace %s", podDescr.Name, ns)) _, err = c.Pods(ns).Create(preStopDescr) expectNoError(err, fmt.Sprintf("creating pod %s", preStopDescr.Name)) deletePreStop := true // At the end of the test, clean up by removing the pod. defer func() { if deletePreStop { By("Deleting the tester pod") c.Pods(ns).Delete(preStopDescr.Name, nil) } }() err = waitForPodRunningInNamespace(c, preStopDescr.Name, ns) expectNoError(err, "waiting for tester pod to start") // Delete the pod with the preStop handler. By("Deleting pre-stop pod") if err := c.Pods(ns).Delete(preStopDescr.Name, nil); err == nil { deletePreStop = false } expectNoError(err, fmt.Sprintf("deleting pod: %s", preStopDescr.Name)) // Validate that the server received the web poke. err = wait.Poll(time.Second*5, time.Second*60, func() (bool, error) { if body, err := c.Get(). Namespace(ns).Prefix("proxy"). Resource("pods"). Name(podDescr.Name). Suffix("read"). DoRaw(); err != nil { By(fmt.Sprintf("Error validating prestop: %v", err)) } else { Logf("Saw: %s", string(body)) state := State{} err := json.Unmarshal(body, &state) if err != nil { Logf("Error parsing: %v", err) return false, nil } if state.Received["prestop"] != 0 { return true, nil } } return false, nil }) expectNoError(err, "validating pre-stop.") }
testHostIP(c, &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "test", Image: "qingyuan/pause", }, }, }, }) }) It("should be schedule with cpu and memory limits", func() { podClient := c.Pods(api.NamespaceDefault) By("creating the pod") name := "pod-update-" + string(util.NewUUID()) value := strconv.Itoa(time.Now().Nanosecond()) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: map[string]string{ "name": "foo", "time": value, }, }, Spec: api.PodSpec{ Containers: []api.Container{ {
Selector: labels, Ports: []api.ServicePort{{ Port: 80, TargetPort: util.NewIntOrStringFromInt(80), }}, }, } _, err := c.Services(ns).Create(service) Expect(err).NotTo(HaveOccurred()) validateEndpointsOrFail(c, ns, serviceName, map[string][]int{}) var names []string defer func() { for _, name := range names { err := c.Pods(ns).Delete(name, nil) Expect(err).NotTo(HaveOccurred()) } }() name1 := "test1" addEndpointPodOrFail(c, ns, name1, labels, []api.ContainerPort{{ContainerPort: 80}}) names = append(names, name1) validateEndpointsOrFail(c, ns, serviceName, map[string][]int{name1: {80}}) name2 := "test2" addEndpointPodOrFail(c, ns, name2, labels, []api.ContainerPort{{ContainerPort: 80}}) names = append(names, name2) validateEndpointsOrFail(c, ns, serviceName, map[string][]int{name1: {80}, name2: {80}})
AfterEach(func() { // Remove any remaining pods from this test if the // replication controller still exists and the replica count // isn't 0. This means the controller wasn't cleaned up // during the test so clean it up here rc, err := c.ReplicationControllers(ns).Get(RCName) if err == nil && rc.Spec.Replicas != 0 { By("Cleaning up the replication controller") err := DeleteRC(c, ns, RCName) expectNoError(err) } By("Removing additional pods if any") for i := 1; i <= minionCount; i++ { name := additionalPodsPrefix + "-" + strconv.Itoa(i) c.Pods(ns).Delete(name, nil) } By(fmt.Sprintf("Destroying namespace for this suite %v", ns)) if err := c.Namespaces().Delete(ns); err != nil { Failf("Couldn't delete ns %s", err) } expectNoError(writePerfData(c, fmt.Sprintf(testContext.OutputDir+"/%s", uuid), "after")) // Verify latency metrics // TODO: We should reset metrics before the test. Currently previous tests influence latency metrics. highLatencyRequests, err := HighLatencyRequests(c, 3*time.Second, util.NewStringSet("events")) expectNoError(err) Expect(highLatencyRequests).NotTo(BeNumerically(">", 0), "There should be no high-latency requests") })
// A basic test to check the deployment of an image using // a replication controller. The image serves its hostname // which is checked for each replica. func ServeImageOrFail(c *client.Client, test string, image string) { ns := api.NamespaceDefault name := "my-hostname-" + test + "-" + string(util.NewUUID()) replicas := 2 // Create a replication controller for a service // that serves its hostname. // The source for the Docker containter qingyuan/serve_hostname is // in contrib/for-demos/serve_hostname By(fmt.Sprintf("Creating replication controller %s", name)) controller, err := c.ReplicationControllers(ns).Create(&api.ReplicationController{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.ReplicationControllerSpec{ Replicas: replicas, Selector: map[string]string{ "name": name, }, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"name": name}, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: name, Image: image, Ports: []api.ContainerPort{{ContainerPort: 9376}}, }, }, }, }, }, }) Expect(err).NotTo(HaveOccurred()) // Cleanup the replication controller when we are done. defer func() { // Resize the replication controller to zero to get rid of pods. By("Cleaning up the replication controller") rcReaper, err := qingctl.ReaperFor("ReplicationController", c) if err != nil { Logf("Failed to cleanup replication controller %v: %v.", controller.Name, err) } if _, err = rcReaper.Stop(ns, controller.Name, 0, nil); err != nil { Logf("Failed to stop replication controller %v: %v.", controller.Name, err) } }() // List the pods, making sure we observe all the replicas. listTimeout := time.Minute label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) pods, err := c.Pods(ns).List(label, fields.Everything()) Expect(err).NotTo(HaveOccurred()) t := time.Now() for { Logf("Controller %s: Found %d pods out of %d", name, len(pods.Items), replicas) if len(pods.Items) == replicas { break } if time.Since(t) > listTimeout { Failf("Controller %s: Gave up waiting for %d pods to come up after seeing only %d pods after %v seconds", name, replicas, len(pods.Items), time.Since(t).Seconds()) } time.Sleep(5 * time.Second) pods, err = c.Pods(ns).List(label, fields.Everything()) Expect(err).NotTo(HaveOccurred()) } By("Ensuring each pod is running") // Wait for the pods to enter the running state. Waiting loops until the pods // are running so non-running pods cause a timeout for this test. for _, pod := range pods.Items { err = waitForPodRunning(c, pod.Name) Expect(err).NotTo(HaveOccurred()) } // Verify that something is listening. By("Trying to dial each unique pod") retryTimeout := 2 * time.Minute retryInterval := 5 * time.Second err = wait.Poll(retryInterval, retryTimeout, podResponseChecker{c, ns, label, name, true, pods}.checkAllResponses) if err != nil { Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds()) } }
func podExists(c *client.Client, podNamespace string, podName string) wait.ConditionFunc { return func() (bool, error) { _, err := c.Pods(podNamespace).Get(podName) return err == nil, nil } }
// Start a client pod using given VolumeSource (exported by startVolumeServer()) // and check that the pod sees the data from the server pod. func testVolumeClient(client *client.Client, config VolumeTestConfig, volume api.VolumeSource, expectedContent string) { By(fmt.Sprint("starting ", config.prefix, " client")) podClient := client.Pods(config.namespace) clientPod := &api.Pod{ TypeMeta: api.TypeMeta{ Kind: "Pod", APIVersion: "v1", }, ObjectMeta: api.ObjectMeta{ Name: config.prefix + "-client", Labels: map[string]string{ "role": config.prefix + "-client", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: config.prefix + "-client", Image: "qingyuan/nginx:1.7.9", Ports: []api.ContainerPort{ { Name: "web", ContainerPort: 80, Protocol: api.ProtocolTCP, }, }, VolumeMounts: []api.VolumeMount{ { Name: config.prefix + "-volume", MountPath: "/usr/share/nginx/html", }, }, }, }, Volumes: []api.Volume{ { Name: config.prefix + "-volume", VolumeSource: volume, }, }, }, } if _, err := podClient.Create(clientPod); err != nil { Failf("Failed to create %s pod: %v", clientPod.Name, err) } expectNoError(waitForPodRunningInNamespace(client, clientPod.Name, config.namespace)) By("reading a web page from the client") body, err := client.Get(). Namespace(config.namespace). Prefix("proxy"). Resource("pods"). Name(clientPod.Name). DoRaw() expectNoError(err, "Cannot read web page: %v", err) Logf("body: %v", string(body)) By("checking the page content") Expect(body).To(ContainSubstring(expectedContent)) }