Change:
return podNames, nil } <del> // restartNodes uses provider to do a restart of all nodes in the cluster, // allowing up to nt per node. func restartNodes(provider string, nt time.Duration) error { switch provider { case "gce", "gke": return migRollingUpdateSelf(nt) default: return fmt.Errorf("restartNodes(...) not implemented for %s", provider) </del> <ins> func restartNodes(f *framework.Framework, nodeNames []string) error { // List old boot IDs. oldBootIDs := make(map[string]string) for _, name := range nodeNames { node, err := f.Client.Nodes().Get(name) if err != nil { return fmt.Errorf("error getting node info before reboot: %s", err) } oldBootIDs[name] = node.Status.NodeInfo.BootID </ins> } <del> } // TODO(marekbiskup): Switch this to MIG recreate-instances. This can be done // with the following bash, but needs to be written in Go: // //   # Step 1: Get instance names. //   list=$(gcloud compute instance-groups --project=${PROJECT} --zone=${ZONE} instances --group=${GROUP} list) //   i="" //   for l in $list; do // 	  i="${l##*/},${i}" //   done // //   # Step 2: Start the recreate. //   output=$(gcloud compute instance-groups managed --project=${PROJECT} --zone=${ZONE} recreate-instances ${GROUP} --instance="${i}") //   op=${output##*:} // //   # Step 3: Wait until it's complete. //   status="" //   while [[ "${status}" != "DONE" ]]; do // 	  output=$(gcloud compute instance-groups managed --zone="${ZONE}" get-operation ${op} | grep status) // 	  status=${output##*:} //   done func migRollingUpdateSelf(nt time.Duration) error { By("getting the name of the template for the managed instance group") tmpl, err := framework.MigTemplate() </del> <ins> // Reboot the nodes. args := []string{ "compute", fmt.Sprintf("--project=%s", framework.TestContext.CloudConfig.ProjectID), "instances", "reset", } args = append(args, nodeNames...) args = append(args, fmt.Sprintf("--zone=%s", framework.TestContext.CloudConfig.Zone)) stdout, stderr, err := framework.RunCmd("gcloud", args...) </ins> if err != nil { <del> return fmt.Errorf("couldn't get MIG template name: %v", err) </del> <ins> return fmt.Errorf("error restarting nodes: %snstdout: %snstderr: %s", err, stdout, stderr) } // Wait for their boot IDs to change. for _, name := range nodeNames { if err := wait.Poll(30*time.Second, 5*time.Minute, func() (bool, error) { node, err := f.Client.Nodes().Get(name) if err != nil { return false, fmt.Errorf("error getting node info after reboot: %s", err) } return node.Status.NodeInfo.BootID != oldBootIDs[name], nil }); err != nil { return fmt.Errorf("error waiting for node %s boot ID to change: %s", name, err) } </ins> } <del> return framework.MigRollingUpdate(tmpl, nt) </del> <ins> return nil </ins> }

Discussion:
This test wants to restart all nodes and make sure that kubernetes survives the process. That's a neat test, but it does the actual restart in a poor way. It does a MIG rolling-update to its own image. If a rolling-update already exists in some sort of error state then all future rolling-updates in that project on an instance group with the same name will fail until someone manually cancels the borked update. We can restart in other less-confusing ways. I suggest one of or . Both seem reasonable to me. cc
ref:
ref/