misc/gce: flesh out enough to boot instances running Camlistore.

Polish remains.

Change-Id: I998cf4d515049e6d0e462fa6c259c39fc1638cf2
This commit is contained in:
Brad Fitzpatrick 2014-08-15 22:18:10 -07:00
parent d2f6f9e057
commit 38cceb30aa
1 changed files with 109 additions and 13 deletions

View File

@ -3,22 +3,26 @@ package main
import (
"bufio"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"sync"
"time"
"camlistore.org/third_party/code.google.com/p/goauth2/oauth"
compute "camlistore.org/third_party/code.google.com/p/google-api-go-client/compute/v1"
storage "camlistore.org/third_party/code.google.com/p/google-api-go-client/storage/v1"
)
var (
projFlag = flag.String("project", "", "name of Project")
zoneFlag = flag.String("zone", "us-central1-a", "GCE zone")
machFlag = flag.String("machinetype", "g1-small", "e.g. n1-standard-1, f1-micro, g1-small")
instanceFlag = flag.String("instance_name", "camlistore-server", "Name of VM instance.")
proj = flag.String("project", "", "name of Project")
zone = flag.String("zone", "us-central1-a", "GCE zone")
mach = flag.String("machinetype", "g1-small", "e.g. n1-standard-1, f1-micro, g1-small")
instance = flag.String("instance_name", "camlistore-server", "Name of VM instance.")
sshPub = flag.String("ssh_public_key", "", "ssh public key file to authorize. Can modify later in Google's web UI anyway.")
)
func readFile(v string) string {
@ -47,18 +51,42 @@ var config = &oauth.Config{
func main() {
flag.Parse()
if *projFlag == "" {
if *proj == "" {
log.Fatalf("Missing --project flag")
}
proj := *projFlag
prefix := "https://www.googleapis.com/compute/v1/projects/" + proj
prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj
imageURL := "https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images/coreos-alpha-402-2-0-v20140807"
machType := prefix + "/zones/" + *zoneFlag + "/machineTypes/" + *machFlag
machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach
tr := &oauth.Transport{
Config: config,
}
cloudConfig := `#cloud-config
coreos:
units:
- name: camlistored.service
command: start
content: |
[Unit]
Description=Camlistore
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/bin/docker run -p 80:80 -p 443:443 camlistore/camlistored
RestartSec=500ms
Restart=always
[Install]
WantedBy=multi-user.target
`
if *sshPub != "" {
key := strings.TrimSpace(readFile(*sshPub))
cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key)
}
tokenCache := oauth.CacheFile("token.dat")
token, err := tokenCache.Token()
if err != nil {
@ -76,10 +104,47 @@ func main() {
}
tr.Token = token
service, _ := compute.New(&http.Client{Transport: tr})
computeService, _ := compute.New(&http.Client{Transport: tr})
storageService, _ := storage.New(&http.Client{Transport: tr})
blobBucket := *proj + "-camlistore-blobs"
configBucket := *proj + "-camlistore-config"
needBucket := map[string]bool{
blobBucket: true,
configBucket: true,
}
buckets, err := storageService.Buckets.List(*proj).Do()
if err != nil {
log.Fatalf("Error listing buckets: %v", err)
}
for _, it := range buckets.Items {
delete(needBucket, it.Name)
}
if len(needBucket) > 0 {
log.Printf("Need to create buckets: %v", needBucket)
var waitBucket sync.WaitGroup
for name := range needBucket {
name := name
waitBucket.Add(1)
go func() {
defer waitBucket.Done()
log.Printf("Creating bucket %s", name)
b, err := storageService.Buckets.Insert(*proj, &storage.Bucket{
Id: name,
Name: name,
}).Do()
if err != nil {
log.Fatalf("Error creating bucket %s: %v", name, err)
}
log.Printf("Created bucket %s: %+v", name, b)
}()
}
waitBucket.Wait()
}
instance := &compute.Instance{
Name: *instanceFlag,
Name: *instance,
Description: "Camlistore server",
MachineType: machType,
Disks: []*compute.AttachedDisk{
@ -93,6 +158,33 @@ func main() {
},
},
},
Tags: &compute.Tags{
Items: []string{"http-server", "https-server"},
},
Metadata: &compute.Metadata{
Items: []*compute.MetadataItems{
{
Key: "camlistore-username",
Value: "test",
},
{
Key: "camlistore-password",
Value: "insecure", // TODO: this won't be cleartext later
},
{
Key: "camlistore-blob-bucket",
Value: "gs://" + blobBucket,
},
{
Key: "camlistore-config-bucket",
Value: "gs://" + configBucket,
},
{
Key: "user-data",
Value: cloudConfig,
},
},
},
NetworkInterfaces: []*compute.NetworkInterface{
&compute.NetworkInterface{
AccessConfigs: []*compute.AccessConfig{
@ -129,19 +221,23 @@ func main() {
})
}
op, err := service.Instances.Insert(*projFlag, *zoneFlag, instance).Do()
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)
for {
op, err := service.ZoneOperations.Get(*projFlag, *zoneFlag, opName).Do()
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":
time.Sleep(1 * time.Second)
log.Printf("Waiting on operation %v", opName)
continue
case "DONE":
if op.Error != nil {
for _, operr := range op.Error.Errors {