blob: 8516134abb239b8255a5ad53af54234e28073d3c [file] [log] [blame]
package main
import (
"flag"
"fmt"
"sort"
"go.skia.org/infra/go/common"
"go.skia.org/infra/go/gce"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/util"
compute "google.golang.org/api/compute/v0.beta"
)
var (
instances = common.NewMultiStringFlag("instance", nil, "Instance(s) to add scopes.")
scopes = common.NewMultiStringFlag("scope", nil, "Scope(s) to add.")
serviceAccount = flag.String("service_account", "", "Override the existing service account on all instances with this one, if set.")
project = flag.String("project", gce.PROJECT_ID_SERVER, "GCE project.")
zone = flag.String("zone", gce.ZONE_DEFAULT, "GCE zone.")
)
func main() {
common.Init()
// Setup.
if instances == nil || len(*instances) == 0 {
sklog.Fatal("--instance is required.")
}
if scopes == nil || len(*scopes) == 0 {
sklog.Fatal("--scope is required.")
}
gcloud, err := gce.NewLocalGCloud(*project, *zone)
if err != nil {
sklog.Fatal(err)
}
is := gcloud.Service().Instances
sklog.Infof("Running on instances: %v", instances)
// Determine the set of scopes for each instance.
emailsByInstance := make(map[string]string, len(*instances))
scopesByInstance := make(map[string]util.StringSet, len(*instances))
for _, name := range *instances {
inst, err := is.Get(*project, *zone, name).Do()
if err != nil {
sklog.Fatal(err)
}
if len(inst.ServiceAccounts) != 1 {
sklog.Fatalf("Instances must have exactly one service account but %s has %d", name, len(inst.ServiceAccounts))
}
emailsByInstance[name] = inst.ServiceAccounts[0].Email
if *serviceAccount != "" {
emailsByInstance[name] = *serviceAccount
}
s := util.NewStringSet(inst.ServiceAccounts[0].Scopes)
for _, scope := range *scopes {
s[scope] = true
}
scopesByInstance[name] = s
sklog.Infof("Scopes for %s:\n%v", name, s.Keys())
}
// For each instance, stop it, apply the scopes, and restart it.
group := util.NewNamedErrGroup()
for name, s := range scopesByInstance {
name := name
instanceScopes := s.Keys()
sort.Strings(instanceScopes)
group.Go(name, func() error {
if err := gcloud.CheckOperation(is.Stop(*project, *zone, name).Do()); err != nil {
return fmt.Errorf("Failed to stop %s: %s", name, err)
}
req := &compute.InstancesSetServiceAccountRequest{
Email: emailsByInstance[name],
Scopes: instanceScopes,
}
if err := gcloud.CheckOperation(is.SetServiceAccount(*project, *zone, name, req).Do()); err != nil {
return fmt.Errorf("Failed to set scopes: %s", err)
}
if err := gcloud.CheckOperation(is.Start(*project, *zone, name).Do()); err != nil {
return fmt.Errorf("Failed to start %s: %s", name, err)
}
return nil
})
}
if err := group.Wait(); err != nil {
sklog.Fatal(err)
}
}