func (p *gceProvider) buildInstance(startAttributes *StartAttributes, imageLink, startupScript string) *compute.Instance { return &compute.Instance{ Description: fmt.Sprintf("Travis CI %s test VM", startAttributes.Language), Disks: []*compute.AttachedDisk{ &compute.AttachedDisk{ Type: "PERSISTENT", Mode: "READ_WRITE", Boot: true, AutoDelete: true, InitializeParams: &compute.AttachedDiskInitializeParams{ SourceImage: imageLink, DiskType: p.ic.DiskType, DiskSizeGb: p.ic.DiskSize, }, }, }, Scheduling: &compute.Scheduling{ Preemptible: true, }, MachineType: p.ic.MachineType.SelfLink, Name: fmt.Sprintf("testing-gce-%s", uuid.NewRandom()), Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ &compute.MetadataItems{ Key: "startup-script", Value: googleapi.String(startupScript), }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Name: "AccessConfig brought to you by travis-worker", Type: "ONE_TO_ONE_NAT", }, }, Network: p.ic.Network.SelfLink, }, }, ServiceAccounts: []*compute.ServiceAccount{ &compute.ServiceAccount{ Email: "default", Scopes: []string{ "https://www.googleapis.com/auth/userinfo.email", compute.DevstorageFullControlScope, compute.ComputeScope, }, }, }, Tags: &compute.Tags{ Items: []string{ "testing", }, }, } }
func TestBasics(t *testing.T) { for _, tc := range []testCase{ { s: schema{}, want: `{}`, }, { s: schema{ ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"}, }, want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`, }, { s: schema{ B: true, F: 1.2, I: 1, Istr: 2, Str: "a", PB: googleapi.Bool(true), PF: googleapi.Float64(1.2), PI: googleapi.Int64(int64(1)), PIStr: googleapi.Int64(int64(2)), PStr: googleapi.String("a"), }, want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`, }, { s: schema{ B: false, F: 0.0, I: 0, Istr: 0, Str: "", PB: googleapi.Bool(false), PF: googleapi.Float64(0.0), PI: googleapi.Int64(int64(0)), PIStr: googleapi.Int64(int64(0)), PStr: googleapi.String(""), }, want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`, }, { s: schema{ B: false, F: 0.0, I: 0, Istr: 0, Str: "", PB: googleapi.Bool(false), PF: googleapi.Float64(0.0), PI: googleapi.Int64(int64(0)), PIStr: googleapi.Int64(int64(0)), PStr: googleapi.String(""), ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"}, }, want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`, }, } { checkMarshalJSON(t, tc) } }
// createInstance starts the creation of the Compute Engine instance and waits for the // result of the creation operation. It should be called after setBuckets and setupHTTPS. func (d *Deployer) createInstance(computeService *compute.Service, ctx context.Context) error { coreosImgURL, err := gceutil.CoreOSImageURL(d.Client) if err != nil { return fmt.Errorf("error looking up latest CoreOS stable image: %v", err) } prefix := projectsAPIURL + d.Conf.Project machType := prefix + "/zones/" + d.Conf.Zone + "/machineTypes/" + d.Conf.Machine config := cloudConfig(d.Conf) instance := &compute.Instance{ Name: d.Conf.Name, Description: "Camlistore server", MachineType: machType, Disks: []*compute.AttachedDisk{ { AutoDelete: true, Boot: true, Type: "PERSISTENT", InitializeParams: &compute.AttachedDiskInitializeParams{ DiskName: d.Conf.Name + "-coreos-stateless-pd", SourceImage: coreosImgURL, }, }, }, Tags: &compute.Tags{ Items: []string{"http-server", "https-server"}, }, Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ { Key: "camlistore-username", Value: googleapi.String(camliUsername), }, { Key: "camlistore-password", Value: googleapi.String(randPassword()), }, { Key: "camlistore-blob-dir", Value: googleapi.String("gs://" + d.Conf.blobDir), }, { Key: "camlistore-config-dir", Value: googleapi.String("gs://" + d.Conf.configDir), }, { Key: "user-data", Value: googleapi.String(config), }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Type: "ONE_TO_ONE_NAT", Name: "External NAT", }, }, Network: prefix + "/global/networks/default", }, }, ServiceAccounts: []*compute.ServiceAccount{ { Email: "default", Scopes: []string{ logging.Scope, compute.DevstorageFullControlScope, compute.ComputeScope, "https://www.googleapis.com/auth/sqlservice", "https://www.googleapis.com/auth/sqlservice.admin", }, }, }, } if d.Conf.Hostname != "" && d.Conf.Hostname != "localhost" { instance.Metadata.Items = append(instance.Metadata.Items, &compute.MetadataItems{ Key: "camlistore-hostname", Value: googleapi.String(d.Conf.Hostname), }) } const localMySQL = false // later if localMySQL { instance.Disks = append(instance.Disks, &compute.AttachedDisk{ AutoDelete: false, Boot: false, Type: "PERSISTENT", InitializeParams: &compute.AttachedDiskInitializeParams{ DiskName: "camlistore-mysql-index-pd", DiskSizeGb: 4, }, }) } if Verbose { d.Print("Creating instance...") } op, err := computeService.Instances.Insert(d.Conf.Project, d.Conf.Zone, instance).Do() if err != nil { return fmt.Errorf("failed to create instance: %v", err) } opName := op.Name if Verbose { d.Printf("Created. Waiting on operation %v", opName) } OpLoop: for { select { case <-ctx.Done(): return ctx.Err() default: } time.Sleep(2 * time.Second) op, err := computeService.ZoneOperations.Get(d.Conf.Project, d.Conf.Zone, opName).Do() if err != nil { return fmt.Errorf("failed to get op %s: %v", opName, err) } switch op.Status { case "PENDING", "RUNNING": if Verbose { d.Printf("Waiting on operation %v", opName) } continue case "DONE": if op.Error != nil { for _, operr := range op.Error.Errors { d.Printf("Error: %+v", operr) } return fmt.Errorf("failed to start.") } if Verbose { d.Printf("Success. %+v", op) } break OpLoop default: return fmt.Errorf("unknown status %q: %+v", op.Status, op) } } return nil }
func main() { flag.Parse() if *staging { if *proj == "symbolic-datum-552" { *proj = "go-dashboard-dev" } if *coordinator == "https://storage.googleapis.com/go-builder-data/coordinator" { *coordinator = "https://storage.googleapis.com/dev-go-builder-data/coordinator" } } if *proj == "" { log.Fatalf("Missing --project flag") } if *staticIP == "" { // Hard-code this, since GCP doesn't let you rename an IP address, and so // this IP is still called "go-buidler-1-ip" in our project, from our old // naming convention plan. switch *proj { case "symbolic-datum-552": *staticIP = "107.178.219.46" case "go-dashboard-dev": *staticIP = "104.154.113.235" } } prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource()) computeService, _ := compute.New(oauthClient) natIP := *staticIP if natIP == "" { // Try to find it by name. aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do() if err != nil { log.Fatal(err) } // https://godoc.org/google.golang.org/api/compute/v1#AddressAggregatedList IPLoop: for _, asl := range aggAddrList.Items { for _, addr := range asl.Addresses { if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" { natIP = addr.Address break IPLoop } } } } cloudConfig := strings.Replace(baseConfig, "$COORDINATOR", *coordinator, 1) if *sshPub != "" { key := strings.TrimSpace(readFile(*sshPub)) cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key) } if os.Getenv("USER") == "bradfitz" { cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= [email protected]") } const maxCloudConfig = 32 << 10 // per compute API docs if len(cloudConfig) > maxCloudConfig { log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig) } instance := &compute.Instance{ Name: *instName, Description: "Go Builder", MachineType: machType, Disks: []*compute.AttachedDisk{instanceDisk(computeService)}, Tags: &compute.Tags{ Items: []string{"http-server", "https-server", "allow-ssh"}, }, Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ { Key: "user-data", Value: googleapi.String(cloudConfig), }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Type: "ONE_TO_ONE_NAT", Name: "External NAT", NatIP: natIP, }, }, Network: prefix + "/global/networks/default", }, }, ServiceAccounts: []*compute.ServiceAccount{ { Email: "default", Scopes: []string{ compute.DevstorageFullControlScope, compute.ComputeScope, compute.CloudPlatformScope, }, }, }, } log.Printf("Creating instance...") op, err := computeService.Instances.Insert(*proj, *zone, instance).Do() if err != nil { log.Fatalf("Failed to create instance: %v", err) } opName := op.Name log.Printf("Created. Waiting on operation %v", opName) OpLoop: for { time.Sleep(2 * time.Second) op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do() if err != nil { log.Fatalf("Failed to get op %s: %v", opName, err) } switch op.Status { case "PENDING", "RUNNING": log.Printf("Waiting on operation %v", opName) continue case "DONE": if op.Error != nil { for _, operr := range op.Error.Errors { log.Printf("Error: %+v", operr) } log.Fatalf("Failed to start.") } log.Printf("Success. %+v", op) break OpLoop default: log.Fatalf("Unknown status %q: %+v", op.Status, op) } } inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do() if err != nil { log.Fatalf("Error getting instance after creation: %v", err) } ij, _ := json.MarshalIndent(inst, "", " ") log.Printf("Instance: %s", ij) }
func (cl *cloudLaunch) createInstance() { inst := cl.lookupInstance() if inst != nil { log.Printf("Instance exists; not re-creating.") return } log.Printf("Instance doesn't exist; creating...") ip := cl.findIP() log.Printf("Found IP: %v", ip) cloudConfig := strings.NewReplacer( "$NAME", cl.Name, "$URL", cl.binaryURL(), "$REBOOT", cl.updateStrategy(), ).Replace(baseConfig) instance := &compute.Instance{ Name: cl.instName(), Description: cl.Name, MachineType: cl.machineTypeURL(), Disks: []*compute.AttachedDisk{cl.instanceDisk()}, Tags: &compute.Tags{ Items: []string{"http-server", "https-server"}, }, Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ { Key: "user-data", Value: googleapi.String(cloudConfig), }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Type: "ONE_TO_ONE_NAT", Name: "External NAT", NatIP: ip, }, }, Network: cl.projectAPIURL() + "/global/networks/default", }, }, ServiceAccounts: []*compute.ServiceAccount{ { Email: "default", Scopes: cl.Scopes, }, }, } log.Printf("Creating instance...") op, err := cl.computeService.Instances.Insert(cl.GCEProjectID, cl.zone(), instance).Do() if err != nil { log.Fatalf("Failed to create instance: %v", err) } opName := op.Name log.Printf("Created. Waiting on operation %v", opName) OpLoop: for { time.Sleep(2 * time.Second) op, err := cl.computeService.ZoneOperations.Get(cl.GCEProjectID, cl.zone(), opName).Do() if err != nil { log.Fatalf("Failed to get op %s: %v", opName, err) } switch op.Status { case "PENDING", "RUNNING": log.Printf("Waiting on operation %v", opName) continue case "DONE": if op.Error != nil { for _, operr := range op.Error.Errors { log.Printf("Error: %+v", operr) } log.Fatalf("Failed to start.") } log.Printf("Success. %+v", op) break OpLoop default: log.Fatalf("Unknown status %q: %+v", op.Status, op) } } inst, err = cl.computeService.Instances.Get(cl.GCEProjectID, cl.zone(), cl.instName()).Do() if err != nil { log.Fatalf("Error getting instance after creation: %v", err) } ij, _ := json.MarshalIndent(inst, "", " ") log.Printf("%s", ij) log.Printf("Instance created.") os.Exit(0) }