// projectHasInstance checks for all the possible zones if there's already an instance for the project. // It returns the name of the zone at the first instance it finds, if any. func (d *Deployer) projectHasInstance() (zone string, err error) { s, err := compute.New(d.Client) if err != nil { return "", err } // TODO(mpl): make use of the handler's cached zones. zl, err := compute.NewZonesService(s).List(d.Conf.Project).Do() if err != nil { return "", fmt.Errorf("could not get a list of zones: %v", err) } computeService, _ := compute.New(d.Client) var zoneOnce sync.Once var grp syncutil.Group errc := make(chan error, 1) zonec := make(chan string, 1) timeout := time.NewTimer(30 * time.Second) defer timeout.Stop() for _, z := range zl.Items { z := z grp.Go(func() error { list, err := computeService.Instances.List(d.Conf.Project, z.Name).Do() if err != nil { return fmt.Errorf("could not list existing instances: %v", err) } if len(list.Items) > 0 { zoneOnce.Do(func() { zonec <- z.Name }) } return nil }) } go func() { errc <- grp.Err() }() // We block until either an instance was found in a zone, or all the instance // listing is done. Or we timed-out. select { case err = <-errc: return "", err case zone = <-zonec: // We voluntarily ignore any listing error if we found at least one instance // because that's what we primarily want to report about. return zone, nil case <-timeout.C: return "", errors.New("timed out") } }
// TODO(bradfitz,mpl): move this to go4.org/cloud/google/gceutil func ZonesOfRegion(hc *http.Client, project, region string) (zones []string, err error) { s, err := compute.New(hc) if err != nil { return nil, err } zl, err := compute.NewZonesService(s).List(project).Do() if err != nil { return nil, fmt.Errorf("could not get a list of zones: %v", err) } if zl.NextPageToken != "" { return nil, errors.New("TODO: more than one page of zones found; use NextPageToken") } for _, z := range zl.Items { if path.Base(z.Region) != region { continue } zones = append(zones, z.Name) } return zones, nil }