github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/h2demo/launch.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 package main 8 9 import ( 10 "bufio" 11 "bytes" 12 "encoding/json" 13 "flag" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "log" 18 "net/http" 19 "os" 20 "strings" 21 "time" 22 23 "golang.org/x/oauth2" 24 "golang.org/x/oauth2/google" 25 compute "google.golang.org/api/compute/v1" 26 ) 27 28 var ( 29 proj = flag.String("project", "symbolic-datum-552", "name of Project") 30 zone = flag.String("zone", "us-central1-a", "GCE zone") 31 mach = flag.String("machinetype", "n1-standard-1", "Machine type") 32 instName = flag.String("instance_name", "http2-demo", "Name of VM instance.") 33 sshPub = flag.String("ssh_public_key", "", "ssh public key file to authorize. Can modify later in Google's web UI anyway.") 34 staticIP = flag.String("static_ip", "130.211.116.44", "Static IP to use. If empty, automatic.") 35 36 writeObject = flag.String("write_object", "", "If non-empty, a VM isn't created and the flag value is Google Cloud Storage bucket/object to write. The contents from stdin.") 37 publicObject = flag.Bool("write_object_is_public", false, "Whether the object created by --write_object should be public.") 38 ) 39 40 func readFile(v string) string { 41 slurp, err := ioutil.ReadFile(v) 42 if err != nil { 43 log.Fatalf("Error reading %s: %v", v, err) 44 } 45 return strings.TrimSpace(string(slurp)) 46 } 47 48 var config = &oauth2.Config{ 49 // The client-id and secret should be for an "Installed Application" when using 50 // the CLI. Later we'll use a web application with a callback. 51 ClientID: readFile("client-id.dat"), 52 ClientSecret: readFile("client-secret.dat"), 53 Endpoint: google.Endpoint, 54 Scopes: []string{ 55 compute.DevstorageFullControlScope, 56 compute.ComputeScope, 57 "https://www.googleapis.com/auth/sqlservice", 58 "https://www.googleapis.com/auth/sqlservice.admin", 59 }, 60 RedirectURL: "urn:ietf:wg:oauth:2.0:oob", 61 } 62 63 const baseConfig = `#cloud-config 64 coreos: 65 units: 66 - name: h2demo.service 67 command: start 68 content: | 69 [Unit] 70 Description=HTTP2 Demo 71 72 [Service] 73 ExecStartPre=/bin/bash -c 'mkdir -p /opt/bin && curl -s -o /opt/bin/h2demo http://storage.googleapis.com/http2-demo-server-tls/h2demo && chmod +x /opt/bin/h2demo' 74 ExecStart=/opt/bin/h2demo --prod 75 RestartSec=5s 76 Restart=always 77 Type=simple 78 79 [Install] 80 WantedBy=multi-user.target 81 ` 82 83 func main() { 84 flag.Parse() 85 if *proj == "" { 86 log.Fatalf("Missing --project flag") 87 } 88 prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj 89 machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach 90 91 const tokenFileName = "token.dat" 92 tokenFile := tokenCacheFile(tokenFileName) 93 tokenSource := oauth2.ReuseTokenSource(nil, tokenFile) 94 token, err := tokenSource.Token() 95 if err != nil { 96 if *writeObject != "" { 97 log.Fatalf("Can't use --write_object without a valid token.dat file already cached.") 98 } 99 log.Printf("Error getting token from %s: %v", tokenFileName, err) 100 log.Printf("Get auth code from %v", config.AuthCodeURL("my-state")) 101 fmt.Print("\nEnter auth code: ") 102 sc := bufio.NewScanner(os.Stdin) 103 sc.Scan() 104 authCode := strings.TrimSpace(sc.Text()) 105 token, err = config.Exchange(oauth2.NoContext, authCode) 106 if err != nil { 107 log.Fatalf("Error exchanging auth code for a token: %v", err) 108 } 109 if err := tokenFile.WriteToken(token); err != nil { 110 log.Fatalf("Error writing to %s: %v", tokenFileName, err) 111 } 112 tokenSource = oauth2.ReuseTokenSource(token, nil) 113 } 114 115 oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) 116 117 if *writeObject != "" { 118 writeCloudStorageObject(oauthClient) 119 return 120 } 121 122 computeService, _ := compute.New(oauthClient) 123 124 natIP := *staticIP 125 if natIP == "" { 126 // Try to find it by name. 127 aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do() 128 if err != nil { 129 log.Fatal(err) 130 } 131 // http://godoc.org/code.google.com/p/google-api-go-client/compute/v1#AddressAggregatedList 132 IPLoop: 133 for _, asl := range aggAddrList.Items { 134 for _, addr := range asl.Addresses { 135 if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" { 136 natIP = addr.Address 137 break IPLoop 138 } 139 } 140 } 141 } 142 143 cloudConfig := baseConfig 144 if *sshPub != "" { 145 key := strings.TrimSpace(readFile(*sshPub)) 146 cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key) 147 } 148 if os.Getenv("USER") == "bradfitz" { 149 cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= bradfitz@papag.bradfitz.com") 150 } 151 const maxCloudConfig = 32 << 10 // per compute API docs 152 if len(cloudConfig) > maxCloudConfig { 153 log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig) 154 } 155 156 instance := &compute.Instance{ 157 Name: *instName, 158 Description: "Go Builder", 159 MachineType: machType, 160 Disks: []*compute.AttachedDisk{instanceDisk(computeService)}, 161 Tags: &compute.Tags{ 162 Items: []string{"http-server", "https-server"}, 163 }, 164 Metadata: &compute.Metadata{ 165 Items: []*compute.MetadataItems{ 166 { 167 Key: "user-data", 168 Value: &cloudConfig, 169 }, 170 }, 171 }, 172 NetworkInterfaces: []*compute.NetworkInterface{ 173 &compute.NetworkInterface{ 174 AccessConfigs: []*compute.AccessConfig{ 175 &compute.AccessConfig{ 176 Type: "ONE_TO_ONE_NAT", 177 Name: "External NAT", 178 NatIP: natIP, 179 }, 180 }, 181 Network: prefix + "/global/networks/default", 182 }, 183 }, 184 ServiceAccounts: []*compute.ServiceAccount{ 185 { 186 Email: "default", 187 Scopes: []string{ 188 compute.DevstorageFullControlScope, 189 compute.ComputeScope, 190 }, 191 }, 192 }, 193 } 194 195 log.Printf("Creating instance...") 196 op, err := computeService.Instances.Insert(*proj, *zone, instance).Do() 197 if err != nil { 198 log.Fatalf("Failed to create instance: %v", err) 199 } 200 opName := op.Name 201 log.Printf("Created. Waiting on operation %v", opName) 202 OpLoop: 203 for { 204 time.Sleep(2 * time.Second) 205 op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do() 206 if err != nil { 207 log.Fatalf("Failed to get op %s: %v", opName, err) 208 } 209 switch op.Status { 210 case "PENDING", "RUNNING": 211 log.Printf("Waiting on operation %v", opName) 212 continue 213 case "DONE": 214 if op.Error != nil { 215 for _, operr := range op.Error.Errors { 216 log.Printf("Error: %+v", operr) 217 } 218 log.Fatalf("Failed to start.") 219 } 220 log.Printf("Success. %+v", op) 221 break OpLoop 222 default: 223 log.Fatalf("Unknown status %q: %+v", op.Status, op) 224 } 225 } 226 227 inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do() 228 if err != nil { 229 log.Fatalf("Error getting instance after creation: %v", err) 230 } 231 ij, _ := json.MarshalIndent(inst, "", " ") 232 log.Printf("Instance: %s", ij) 233 } 234 235 func instanceDisk(svc *compute.Service) *compute.AttachedDisk { 236 const imageURL = "https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images/coreos-stable-444-5-0-v20141016" 237 diskName := *instName + "-disk" 238 239 return &compute.AttachedDisk{ 240 AutoDelete: true, 241 Boot: true, 242 Type: "PERSISTENT", 243 InitializeParams: &compute.AttachedDiskInitializeParams{ 244 DiskName: diskName, 245 SourceImage: imageURL, 246 DiskSizeGb: 50, 247 }, 248 } 249 } 250 251 func writeCloudStorageObject(httpClient *http.Client) { 252 content := os.Stdin 253 const maxSlurp = 1 << 20 254 var buf bytes.Buffer 255 n, err := io.CopyN(&buf, content, maxSlurp) 256 if err != nil && err != io.EOF { 257 log.Fatalf("Error reading from stdin: %v, %v", n, err) 258 } 259 contentType := http.DetectContentType(buf.Bytes()) 260 261 req, err := http.NewRequest("PUT", "https://storage.googleapis.com/"+*writeObject, io.MultiReader(&buf, content)) 262 if err != nil { 263 log.Fatal(err) 264 } 265 req.Header.Set("x-goog-api-version", "2") 266 if *publicObject { 267 req.Header.Set("x-goog-acl", "public-read") 268 } 269 req.Header.Set("Content-Type", contentType) 270 res, err := httpClient.Do(req) 271 if err != nil { 272 log.Fatal(err) 273 } 274 if res.StatusCode != 200 { 275 res.Write(os.Stderr) 276 log.Fatalf("Failed.") 277 } 278 log.Printf("Success.") 279 os.Exit(0) 280 } 281 282 type tokenCacheFile string 283 284 func (f tokenCacheFile) Token() (*oauth2.Token, error) { 285 slurp, err := ioutil.ReadFile(string(f)) 286 if err != nil { 287 return nil, err 288 } 289 t := new(oauth2.Token) 290 if err := json.Unmarshal(slurp, t); err != nil { 291 return nil, err 292 } 293 return t, nil 294 } 295 296 func (f tokenCacheFile) WriteToken(t *oauth2.Token) error { 297 jt, err := json.Marshal(t) 298 if err != nil { 299 return err 300 } 301 return ioutil.WriteFile(string(f), jt, 0600) 302 }