func checkTunnelsCorrect(t *testing.T, tunnelList *SSHTunnelList, addresses []string) { if err := wait.Poll(100*time.Millisecond, 2*time.Second, func() (bool, error) { return hasCorrectTunnels(tunnelList, addresses), nil }); err != nil { t.Errorf("Error waiting for tunnels to reach expected state: %v. Expected %v, had %v", err, addresses, tunnelList) } }
func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error { ds, err := reaper.Extensions().DaemonSets(namespace).Get(name) if err != nil { return err } // We set the nodeSelector to a random label. This label is nearly guaranteed // to not be set on any node so the DameonSetController will start deleting // daemon pods. Once it's done deleting the daemon pods, it's safe to delete // the DaemonSet. ds.Spec.Template.Spec.NodeSelector = map[string]string{ string(util.NewUUID()): string(util.NewUUID()), } // force update to avoid version conflict ds.ResourceVersion = "" if ds, err = reaper.Extensions().DaemonSets(namespace).Update(ds); err != nil { return err } // Wait for the daemon set controller to kill all the daemon pods. if err := wait.Poll(reaper.pollInterval, reaper.timeout, func() (bool, error) { updatedDS, err := reaper.Extensions().DaemonSets(namespace).Get(name) if err != nil { return false, nil } return updatedDS.Status.CurrentNumberScheduled+updatedDS.Status.NumberMisscheduled == 0, nil }); err != nil { return err } return reaper.Extensions().DaemonSets(namespace).Delete(name) }
func waitForWaitingQueueToFill(q DelayingInterface) error { return wait.Poll(1*time.Millisecond, 10*time.Second, func() (done bool, err error) { if len(q.(*delayingType).waitingForAddCh) == 0 { return true, nil } return false, nil }) }
func waitForAdded(t *testing.T, q DelayingInterface, depth int) error { err := wait.Poll(1*time.Millisecond, 20*time.Second, func() (done bool, err error) { if q.Len() == depth { return true, nil } return false, nil }) if err != nil { t.Logf("failed: len=%v, everything=%#v", q.Len(), q) } return err }
// Internal implementation of runSSHCommand, for testing func runSSHCommand(dialer sshDialer, cmd, user, host string, signer ssh.Signer, retry bool) (string, string, int, error) { if user == "" { user = os.Getenv("USER") } // Setup the config, dial the server, and open a session. config := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)}, } client, err := dialer.Dial("tcp", host, config) if err != nil && retry { err = wait.Poll(5*time.Second, 20*time.Second, func() (bool, error) { fmt.Printf("error dialing %s@%s: '%v', retrying\n", user, host, err) if client, err = dialer.Dial("tcp", host, config); err != nil { return false, nil } return true, nil }) } if err != nil { return "", "", 0, fmt.Errorf("error getting SSH client to %s@%s: '%v'", user, host, err) } session, err := client.NewSession() if err != nil { return "", "", 0, fmt.Errorf("error creating session to %s@%s: '%v'", user, host, err) } defer session.Close() // Run the command. code := 0 var bout, berr bytes.Buffer session.Stdout, session.Stderr = &bout, &berr if err = session.Run(cmd); err != nil { // Check whether the command failed to run or didn't complete. if exiterr, ok := err.(*ssh.ExitError); ok { // If we got an ExitError and the exit code is nonzero, we'll // consider the SSH itself successful (just that the command run // errored on the host). if code = exiterr.ExitStatus(); code != 0 { err = nil } } else { // Some other kind of error happened (e.g. an IOError); consider the // SSH unsuccessful. err = fmt.Errorf("failed running `%s` on %s@%s: '%v'", cmd, user, host, err) } } return bout.String(), berr.String(), code, err }
func (reaper *DeploymentReaper) updateDeploymentWithRetries(namespace, name string, applyUpdate updateDeploymentFunc) (deployment *extensions.Deployment, err error) { deployments := reaper.Extensions().Deployments(namespace) err = wait.Poll(10*time.Millisecond, 1*time.Minute, func() (bool, error) { if deployment, err = deployments.Get(name); err != nil { return false, err } // Apply the update, then attempt to push it to the apiserver. applyUpdate(deployment) if deployment, err = deployments.Update(deployment); err == nil { return true, nil } return false, nil }) return deployment, err }
// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails. func (le *LeaderElector) renew() { stop := make(chan struct{}) wait.Until(func() { err := wait.Poll(le.config.RetryPeriod, le.config.RenewDeadline, func() (bool, error) { return le.tryAcquireOrRenew(), nil }) le.maybeReportTransition() if err == nil { glog.V(4).Infof("succesfully renewed lease %v/%v", le.config.EndpointsMeta.Namespace, le.config.EndpointsMeta.Name) return } le.config.EventRecorder.Eventf(&api.Endpoints{ObjectMeta: le.config.EndpointsMeta}, api.EventTypeNormal, "%v stopped leading", le.config.Identity) glog.Infof("failed to renew lease %v/%v", le.config.EndpointsMeta.Namespace, le.config.EndpointsMeta.Name) close(stop) }, 0, stop) }
// UpdatePodWithRetries updates a pod with given applyUpdate function. Note that pod not found error is ignored. // The returned bool value can be used to tell if the pod is actually updated. func UpdatePodWithRetries(podClient unversionedcore.PodInterface, pod *api.Pod, applyUpdate updatePodFunc) (*api.Pod, bool, error) { var err error var podUpdated bool oldPod := pod if err = wait.Poll(10*time.Millisecond, 1*time.Minute, func() (bool, error) { pod, err = podClient.Get(oldPod.Name) if err != nil { return false, err } // Apply the update, then attempt to push it to the apiserver. if err = applyUpdate(pod); err != nil { return false, err } if pod, err = podClient.Update(pod); err == nil { // Update successful. return true, nil } // TODO: don't retry on perm-failed errors and handle them gracefully // Update could have failed due to conflict error. Try again. return false, nil }); err == nil { // When there's no error, we've updated this pod. podUpdated = true } // Handle returned error from wait poll if err == wait.ErrWaitTimeout { err = fmt.Errorf("timed out trying to update pod: %+v", oldPod) } // Ignore the pod not found error, but the pod isn't updated. if errors.IsNotFound(err) { glog.V(4).Infof("%s %s/%s is not found, skip updating it.", oldPod.Kind, oldPod.Namespace, oldPod.Name) err = nil } // Ignore the precondition violated error, but the pod isn't updated. if err == errorsutil.ErrPreconditionViolated { glog.V(4).Infof("%s %s/%s precondition doesn't hold, skip updating it.", oldPod.Kind, oldPod.Namespace, oldPod.Name) err = nil } // If the error is non-nil the returned pod cannot be trusted; if podUpdated is false, the pod isn't updated; // if the error is nil and podUpdated is true, the returned pod contains the applied update. return pod, podUpdated, err }
// cleanupWithClients performs cleanup tasks after the rolling update. Update // process related annotations are removed from oldRc and newRc. The // CleanupPolicy on config is executed. func (r *RollingUpdater) cleanupWithClients(oldRc, newRc *api.ReplicationController, config *RollingUpdaterConfig) error { // Clean up annotations var err error newRc, err = r.c.ReplicationControllers(r.ns).Get(newRc.Name) if err != nil { return err } applyUpdate := func(rc *api.ReplicationController) { delete(rc.Annotations, sourceIdAnnotation) delete(rc.Annotations, desiredReplicasAnnotation) } if newRc, err = updateRcWithRetries(r.c, r.ns, newRc, applyUpdate); err != nil { return err } if err = wait.Poll(config.Interval, config.Timeout, client.ControllerHasDesiredReplicas(r.c, newRc)); err != nil { return err } newRc, err = r.c.ReplicationControllers(r.ns).Get(newRc.Name) if err != nil { return err } switch config.CleanupPolicy { case DeleteRollingUpdateCleanupPolicy: // delete old rc fmt.Fprintf(config.Out, "Update succeeded. Deleting %s\n", oldRc.Name) return r.c.ReplicationControllers(r.ns).Delete(oldRc.Name) case RenameRollingUpdateCleanupPolicy: // delete old rc fmt.Fprintf(config.Out, "Update succeeded. Deleting old controller: %s\n", oldRc.Name) if err := r.c.ReplicationControllers(r.ns).Delete(oldRc.Name); err != nil { return err } fmt.Fprintf(config.Out, "Renaming %s to %s\n", newRc.Name, oldRc.Name) return Rename(r.c, newRc, oldRc.Name) case PreserveRollingUpdateCleanupPolicy: return nil default: return nil } }
func TestSimpleQueue(t *testing.T) { fakeClock := util.NewFakeClock(time.Now()) q := newDelayingQueue(fakeClock) first := "foo" q.AddAfter(first, 50*time.Millisecond) if err := waitForWaitingQueueToFill(q); err != nil { t.Fatalf("unexpected err: %v", err) } if q.Len() != 0 { t.Errorf("should not have added") } fakeClock.Step(60 * time.Millisecond) if err := waitForAdded(t, q, 1); err != nil { t.Errorf("should have added") } item, _ := q.Get() q.Done(item) // step past the next heartbeat fakeClock.Step(10 * time.Second) err := wait.Poll(1*time.Millisecond, 30*time.Millisecond, func() (done bool, err error) { if q.Len() > 0 { return false, fmt.Errorf("added to queue") } return false, nil }) if err != wait.ErrWaitTimeout { t.Errorf("expected timeout, got: %v", err) } if q.Len() != 0 { t.Errorf("should not have added") } }
func (vm *volumeManager) WaitForAttachAndMount(pod *api.Pod) error { expectedVolumes := getExpectedVolumes(pod) if len(expectedVolumes) == 0 { // No volumes to verify return nil } glog.V(3).Infof("Waiting for volumes to attach and mount for pod %q", format.Pod(pod)) uniquePodName := volumehelper.GetUniquePodName(pod) // Some pods expect to have Setup called over and over again to update. // Remount plugins for which this is true. (Atomically updating volumes, // like Downward API, depend on this to update the contents of the volume). vm.desiredStateOfWorldPopulator.ReprocessPod(uniquePodName) vm.actualStateOfWorld.MarkRemountRequired(uniquePodName) err := wait.Poll( podAttachAndMountRetryInterval, podAttachAndMountTimeout, vm.verifyVolumesMountedFunc(uniquePodName, expectedVolumes)) if err != nil { // Timeout expired ummountedVolumes := vm.getUnmountedVolumes(uniquePodName, expectedVolumes) if len(ummountedVolumes) == 0 { return nil } return fmt.Errorf( "timeout expired waiting for volumes to attach/mount for pod %q/%q. list of unattached/unmounted volumes=%v", pod.Name, pod.Namespace, ummountedVolumes) } glog.V(3).Infof("All volumes are attached and mounted for pod %q", format.Pod(pod)) return nil }
func TestCleanUp(t *testing.T) { m := newTestManager() for _, probeType := range [...]probeType{liveness, readiness} { key := probeKey{testPodUID, testContainerName, probeType} w := newTestWorker(m, probeType, api.Probe{}) m.statusManager.SetPodStatus(w.pod, getTestRunningStatus()) go w.run() m.workers[key] = w // Wait for worker to run. condition := func() (bool, error) { ready, _ := resultsManager(m, probeType).Get(testContainerID) return ready == results.Success, nil } if ready, _ := condition(); !ready { if err := wait.Poll(100*time.Millisecond, wait.ForeverTestTimeout, condition); err != nil { t.Fatalf("[%s] Error waiting for worker ready: %v", probeType, err) } } for i := 0; i < 10; i++ { w.stop() // Stop should be callable multiple times without consequence. } if err := waitForWorkerExit(m, []probeKey{key}); err != nil { t.Fatalf("[%s] error waiting for worker exit: %v", probeType, err) } if _, ok := resultsManager(m, probeType).Get(testContainerID); ok { t.Errorf("[%s] Expected result to be cleared.", probeType) } if _, ok := m.workers[key]; ok { t.Errorf("[%s] Expected worker to be cleared.", probeType) } } }