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: unversioned.TypeMeta{ Kind: "Pod", }, ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: name, Image: image, }, }, DNSPolicy: api.DNSDefault, }, } _, err := c.Pods(ns).Create(pod) expectNoError(err) expectNoError(waitForPodRunningInNamespace(c, name, ns)) }
// waitForPodCondition waits for a pod in state defined by a condition (func) func waitForPodCondition(kubeClient *unversioned.Client, ns, podName string, condition func(pod *api.Pod) (bool, error), interval, timeout time.Duration) error { err := wait.PollImmediate(interval, timeout, func() (bool, error) { pod, err := kubeClient.Pods(ns).Get(podName) if err != nil { if apierrs.IsNotFound(err) { return false, nil } } done, err := condition(pod) if err != nil { return false, err } if done { return true, nil } return false, nil }) if err != nil { return fmt.Errorf("timed out waiting to observe own status as Running") } return nil }
func forEachPod(c *client.Client, ns, selectorKey, selectorValue string, fn func(api.Pod)) { pods := []*api.Pod{} for t := time.Now(); time.Since(t) < podListTimeout; time.Sleep(poll) { selector := labels.SelectorFromSet(labels.Set(map[string]string{selectorKey: selectorValue})) options := api.ListOptions{LabelSelector: selector} podList, err := c.Pods(ns).List(options) Expect(err).NotTo(HaveOccurred()) for _, pod := range podList.Items { if pod.Status.Phase == api.PodPending || pod.Status.Phase == api.PodRunning { pods = append(pods, &pod) } } if len(pods) > 0 { break } } if pods == nil || len(pods) == 0 { Failf("No pods found") } for _, pod := range pods { err := waitForPodRunningInNamespace(c, pod.Name, ns) Expect(err).NotTo(HaveOccurred()) fn(*pod) } }
func waitForAllCaPodsReadyInNamespace(f *framework.Framework, c *client.Client) error { var notready []string for start := time.Now(); time.Now().Before(start.Add(scaleUpTimeout)); time.Sleep(20 * time.Second) { pods, err := c.Pods(f.Namespace.Name).List(api.ListOptions{}) if err != nil { return fmt.Errorf("failed to get pods: %v", err) } notready = make([]string, 0) for _, pod := range pods.Items { ready := false for _, c := range pod.Status.Conditions { if c.Type == api.PodReady && c.Status == api.ConditionTrue { ready = true } } if !ready { notready = append(notready, pod.Name) } } if len(notready) == 0 { glog.Infof("All pods ready") return nil } glog.Infof("Some pods are not ready yet: %v", notready) } glog.Info("Timeout on waiting for pods being ready") glog.Info(framework.RunKubectlOrDie("get", "pods", "-o", "json", "--all-namespaces")) glog.Info(framework.RunKubectlOrDie("get", "nodes", "-o", "json")) // Some pods are still not running. return fmt.Errorf("Some pods are still not running: %v", notready) }
// Delete the passed in pod. func deletePod(f *framework.Framework, c *client.Client, ns string, pod *api.Pod) error { framework.Logf("Deleting pod %v", pod.Name) err := c.Pods(ns).Delete(pod.Name, nil) if err != nil { return fmt.Errorf("Pod %v encountered a delete error: %v", pod.Name, err) } // Wait for pod to terminate err = f.WaitForPodTerminated(pod.Name, "") if err != nil && !apierrs.IsNotFound(err) { return fmt.Errorf("Pod %v will not teminate: %v", pod.Name, err) } // Re-get the pod to double check that it has been deleted; expect err // Note: Get() writes a log error if the pod is not found _, err = c.Pods(ns).Get(pod.Name) if err == nil { return fmt.Errorf("Pod %v has been deleted but able to re-Get the deleted pod", pod.Name) } if !apierrs.IsNotFound(err) { return fmt.Errorf("Pod %v has been deleted but still exists: %v", pod.Name, err) } framework.Logf("Ignore \"not found\" error above. Pod %v successfully deleted", pod.Name) return nil }
func createRunningPod(wg *sync.WaitGroup, c *client.Client, name, ns, image string, labels map[string]string, cpuRequest, memRequest resource.Quantity) { defer GinkgoRecover() defer wg.Done() pod := &api.Pod{ TypeMeta: unversioned.TypeMeta{ Kind: "Pod", }, ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: name, Image: image, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceCPU: cpuRequest, api.ResourceMemory: memRequest, }, }, }, }, DNSPolicy: api.DNSDefault, }, } _, err := c.Pods(ns).Create(pod) expectNoError(err) expectNoError(waitForPodRunningInNamespace(c, name, ns)) }
// podsOnNodes returns true when all of the selected pods exist on a node. func podsOnNodes(c *client.Client, podNamespace string, labelSelector labels.Selector) wait.ConditionFunc { // Wait until all pods are running on the node. return func() (bool, error) { options := api.ListOptions{LabelSelector: labelSelector} pods, err := c.Pods(podNamespace).List(options) 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("%s/%s", 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 { glog.Infof("Pod %q is not running, status: %v", podString, pod.Status.Phase) return false, nil } } return true, nil } }
// Waits until all existing pods are scheduled and returns their amount. func waitForStableCluster(c *client.Client) int { timeout := 10 * time.Minute startTime := time.Now() allPods, err := c.Pods(api.NamespaceAll).List(api.ListOptions{}) framework.ExpectNoError(err) // API server returns also Pods that succeeded. We need to filter them out. currentPods := make([]api.Pod, 0, len(allPods.Items)) for _, pod := range allPods.Items { if pod.Status.Phase != api.PodSucceeded && pod.Status.Phase != api.PodFailed { currentPods = append(currentPods, pod) } } allPods.Items = currentPods scheduledPods, currentlyNotScheduledPods := getPodsScheduled(allPods) for len(currentlyNotScheduledPods) != 0 { time.Sleep(2 * time.Second) allPods, err := c.Pods(api.NamespaceAll).List(api.ListOptions{}) framework.ExpectNoError(err) scheduledPods, currentlyNotScheduledPods = getPodsScheduled(allPods) if startTime.Add(timeout).Before(time.Now()) { framework.Failf("Timed out after %v waiting for stable cluster.", timeout) break } } return len(scheduledPods) }
// groupPods divides pods running on <node> into those which can't be deleted and the others func groupPods(client *kube_client.Client, node *kube_api.Node) ([]*kube_api.Pod, []*kube_api.Pod, error) { podsOnNode, err := client.Pods(kube_api.NamespaceAll).List( kube_api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": node.Name})}) if err != nil { return []*kube_api.Pod{}, []*kube_api.Pod{}, err } requiredPods := make([]*kube_api.Pod, 0) otherPods := make([]*kube_api.Pod, 0) for i := range podsOnNode.Items { pod := &podsOnNode.Items[i] creatorRef, err := ca_simulator.CreatorRefKind(pod) if err != nil { return []*kube_api.Pod{}, []*kube_api.Pod{}, err } if ca_simulator.IsMirrorPod(pod) || creatorRef == "DaemonSet" || isCriticalPod(pod) { requiredPods = append(requiredPods, pod) } else { otherPods = append(otherPods, pod) } } return requiredPods, otherPods, nil }
func createPodWithSpec(c *client.Client, pod *api.Pod) (*api.Pod, error) { // Manually assign pod to node because we don't run the scheduler in node // e2e tests. assignPodToNode(pod) createdPod, err := c.Pods(pod.Namespace).Create(pod) return createdPod, err }
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 // situation 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.NamespaceSystem).List(labels.Set{"k8s-app": rcLabel}.AsSelector(), fields.Everything()) 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.NamespaceSystem).List(labels.Set(rc.Spec.Selector).AsSelector(), fields.Everything()) if err != nil { return nil, err } for _, pod := range podList.Items { if pod.DeletionTimestamp != nil { continue } expectedPods = append(expectedPods, string(pod.UID)) } } } return expectedPods, nil }
func podWatchFunc(c *client.Client, ns string) func(options api.ListOptions) (watch.Interface, error) { return func(opts api.ListOptions) (watch.Interface, error) { return c.Pods(ns).Watch(api.ListOptions{ LabelSelector: labels.Everything(), }) } }
func podListFunc(c *client.Client, ns string) func(options api.ListOptions) (runtime.Object, error) { return func(opts api.ListOptions) (runtime.Object, error) { return c.Pods(ns).List(api.ListOptions{ LabelSelector: labels.Everything(), }) } }
// Simplified version of RunRC, that does not create RC, but creates plain Pods. // Optionally waits for pods to start running (if waitForRunning == true). // The number of replicas must be non-zero. func StartPods(c *client.Client, replicas int, namespace string, podNamePrefix string, pod api.Pod, waitForRunning bool, logFunc func(fmt string, args ...interface{})) error { // no pod to start if replicas < 1 { panic("StartPods: number of replicas must be non-zero") } startPodsID := string(uuid.NewUUID()) // So that we can label and find them for i := 0; i < replicas; i++ { podName := fmt.Sprintf("%v-%v", podNamePrefix, i) pod.ObjectMeta.Name = podName pod.ObjectMeta.Labels["name"] = podName pod.ObjectMeta.Labels["startPodsID"] = startPodsID pod.Spec.Containers[0].Name = podName _, err := c.Pods(namespace).Create(&pod) if err != nil { return err } } logFunc("Waiting for running...") if waitForRunning { label := labels.SelectorFromSet(labels.Set(map[string]string{"startPodsID": startPodsID})) err := WaitForPodsWithLabelRunning(c, namespace, label) if err != nil { return fmt.Errorf("Error waiting for %d pods to be running - probably a timeout: %v", replicas, err) } } return nil }
// getLBDetails returns runtime information about the pod (name, IP) and replication // controller (namespace and name) // This is required to watch for changes in annotations or configuration (ConfigMap) func getLBDetails(kubeClient *unversioned.Client) (rc *lbInfo, err error) { podIP := os.Getenv("POD_IP") podName := os.Getenv("POD_NAME") podNs := os.Getenv("POD_NAMESPACE") pod, _ := kubeClient.Pods(podNs).Get(podName) if pod == nil { return } annotations := pod.Annotations["kubernetes.io/created-by"] var sref api.SerializedReference err = json.Unmarshal([]byte(annotations), &sref) if err != nil { return } if sref.Reference.Kind == "ReplicationController" { rc = &lbInfo{ RCNamespace: sref.Reference.Namespace, RCName: sref.Reference.Name, PodIP: podIP, Podname: podName, PodNamespace: podNs, } } return }
func checkMirrorPodDisappear(cl *client.Client, name, namespace string) error { _, err := cl.Pods(namespace).Get(name) if errors.IsNotFound(err) { return nil } return goerrors.New("pod not disappear") }
// WaitForPodCreationServiceAccounts ensures that the service account needed for pod creation exists // and that the cache for the admission control that checks for pod tokens has caught up to allow // pod creation. func WaitForPodCreationServiceAccounts(client *kclient.Client, namespace string) error { if err := WaitForServiceAccounts(client, namespace, []string{bootstrappolicy.DefaultServiceAccountName}); err != nil { return err } testPod := &kapi.Pod{} testPod.GenerateName = "test" testPod.Spec.Containers = []kapi.Container{ { Name: "container", Image: "openshift/origin-pod:latest", }, } return wait.PollImmediate(time.Second, PodCreationWaitTimeout, func() (bool, error) { pod, err := client.Pods(namespace).Create(testPod) if err != nil { glog.Warningf("Error attempting to create test pod: %v", err) return false, nil } err = client.Pods(namespace).Delete(pod.Name, kapi.NewDeleteOptions(0)) if err != nil { return false, err } return true, nil }) }
func verifyResult(c *client.Client, podName string, ns string, oldNotScheduled int) { allPods, err := c.Pods(api.NamespaceAll).List(labels.Everything(), fields.Everything()) expectNoError(err) scheduledPods, notScheduledPods := getPodsScheduled(allPods) schedEvents, err := c.Events(ns).List( labels.Everything(), fields.Set{ "involvedObject.kind": "Pod", "involvedObject.name": podName, "involvedObject.namespace": ns, "source": "scheduler", "reason": "FailedScheduling", }.AsSelector()) expectNoError(err) printed := false printOnce := func(msg string) string { if !printed { printed = true return msg } else { return "" } } Expect(len(notScheduledPods)).To(Equal(1+oldNotScheduled), printOnce(fmt.Sprintf("Not scheduled Pods: %#v", notScheduledPods))) Expect(schedEvents.Items).ToNot(BeEmpty(), printOnce(fmt.Sprintf("Scheduled Pods: %#v", scheduledPods))) }
// GetRequiredPodsForNode returns a list od pods that would appear on the node if the // node was just created (like deamonset and manifest-run pods). It reuses kubectl // drain command to get the list. func GetRequiredPodsForNode(nodename string, client *kube_client.Client) ([]*kube_api.Pod, error) { podsToRemoveList, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, nodename, kube_api.Codecs.UniversalDecoder(), true, true) if err != nil { return []*kube_api.Pod{}, err } podsToRemoveMap := make(map[string]struct{}) for _, pod := range podsToRemoveList { podsToRemoveMap[pod.SelfLink] = struct{}{} } allPodList, err := client.Pods(kube_api.NamespaceAll).List( kube_api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodename})}) if err != nil { return []*kube_api.Pod{}, err } podsOnNewNode := make([]*kube_api.Pod, 0) for i, pod := range allPodList.Items { if _, found := podsToRemoveMap[pod.SelfLink]; !found { podsOnNewNode = append(podsOnNewNode, &allPodList.Items[i]) } } return podsOnNewNode, nil }
// createOutOfDiskPod creates a pod in the given namespace with the requested amount of CPU. func createOutOfDiskPod(c *client.Client, ns, name string, milliCPU int64) { podClient := c.Pods(ns) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "pause", Image: "beta.gcr.io/google_containers/pause:2.0", Resources: api.ResourceRequirements{ Requests: api.ResourceList{ // Request enough CPU to fit only two pods on a given node. api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), }, }, }, }, }, } _, err := podClient.Create(pod) expectNoError(err) }
// getLBDetails returns runtime information about the pod (name, IP) and replication // controller (namespace and name) // This is required to watch for changes in annotations or configuration (ConfigMap) func getLBDetails(kubeClient *unversioned.Client) (rc *lbInfo, err error) { podIP := os.Getenv("POD_IP") podName := os.Getenv("POD_NAME") podNs := os.Getenv("POD_NAMESPACE") pod, _ := kubeClient.Pods(podNs).Get(podName) if pod == nil { return nil, errMissingPodInfo } annotations := pod.Annotations["kubernetes.io/created-by"] var sref api.SerializedReference err = json.Unmarshal([]byte(annotations), &sref) if err != nil { return nil, err } rc = &lbInfo{ ObjectName: sref.Reference.Name, PodIP: podIP, Podname: podName, PodNamespace: podNs, } switch sref.Reference.Kind { case "ReplicationController": rc.DeployType = &api.ReplicationController{} return rc, nil case "DaemonSet": rc.DeployType = &extensions.DaemonSet{} return rc, nil default: return nil, errInvalidKind } }
func createPodWithSpec(c *client.Client, pod *api.Pod) (*api.Pod, error) { // Manually assign pod to node because we don't run the scheduler in node // e2e tests. pod.Spec.NodeName = framework.TestContext.NodeName createdPod, err := c.Pods(pod.Namespace).Create(pod) return createdPod, err }
// 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, ns string, pod *api.Pod) { podClient := c.Pods(ns) By("creating pod") defer podClient.Delete(pod.Name, api.NewDeleteOptions(0)) if _, err := podClient.Create(pod); err != nil { Failf("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 waitForPodRunning(c *client.Client, pod *api.Pod, out io.Writer) (status api.PodPhase, err error) { for { pod, err := c.Pods(pod.Namespace).Get(pod.Name) if err != nil { return api.PodUnknown, err } ready := false if pod.Status.Phase == api.PodRunning { ready = true for _, status := range pod.Status.ContainerStatuses { if !status.Ready { ready = false break } } if ready { return api.PodRunning, nil } } if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed { return pod.Status.Phase, nil } fmt.Fprintf(out, "Waiting for pod %s/%s to be running, status is %s, pod ready: %v\n", pod.Namespace, pod.Name, pod.Status.Phase, ready) time.Sleep(2 * time.Second) continue } }
func podsCreated(c *client.Client, ns, name string, replicas int) (*api.PodList, error) { timeout := 2 * time.Minute // List the pods, making sure we observe all the replicas. label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) { pods, err := c.Pods(ns).List(label, fields.Everything()) if err != nil { return nil, err } created := []api.Pod{} for _, pod := range pods.Items { if pod.DeletionTimestamp != nil { continue } created = append(created, pod) } Logf("Pod name %s: Found %d pods out of %d", name, len(created), replicas) if len(created) == replicas { pods.Items = created return pods, nil } } return nil, fmt.Errorf("Pod name %s: Gave up waiting %v for %d pods to come up", name, timeout, replicas) }
func runSchedulerNoPhantomPodsTest(client *client.Client) { pod := &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{ { Name: "c1", Image: "kubernetes/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, longTestTimeout, 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, longTestTimeout, 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, api.NewDeleteOptions(0)) 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, longTestTimeout, podRunning(client, baz.Namespace, baz.Name)); err != nil { if pod, perr := client.Pods(api.NamespaceDefault).Get("phantom.bar"); perr == nil { glog.Fatalf("FAILED: 'phantom.bar' was never deleted: %#v, err: %v", pod, err) } else { glog.Fatalf("FAILED: (Scheduler probably didn't process deletion of 'phantom.bar') Pod never started running: err: %v, perr: %v", err, perr) } } glog.Info("Scheduler doesn't make phantom pods: test passed.") }
func createPodWithSpec(c *client.Client, pod *api.Pod) (*api.Pod, error) { // Manually assign pod to node because we don't run the scheduler in node // e2e tests. // TODO: This should also be a shared utility function. setNodeNameForPod(pod) createdPod, err := c.Pods(pod.Namespace).Create(pod) return createdPod, err }
func cleanupPods(c *client.Client, ns string) { By("Removing all pods in namespace " + ns) pods, err := c.Pods(ns).List(labels.Everything(), fields.Everything()) expectNoError(err) opt := api.NewDeleteOptions(0) for _, p := range pods.Items { expectNoError(c.Pods(ns).Delete(p.ObjectMeta.Name, opt)) } }
func newPodOnNode(c *client.Client, namespace, podName, nodeName string) error { pod, err := c.Pods(namespace).Create(podOnNode(podName, nodeName, serveHostnameImage)) if err == nil { Logf("Created pod %s on node %s", pod.ObjectMeta.Name, nodeName) } else { Logf("Failed to create pod %s on node %s: %v", podName, nodeName, err) } return err }