aboutsummaryrefslogtreecommitdiffstats
path: root/gce
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-10-07 18:56:45 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-10-07 18:56:45 +0200
commitd21c3c878c8965786d39a5d73bbe22792b0a6ccd (patch)
tree5c72441d9a36e0f7e2ed91e1c3e6243966757acc /gce
parent2da6f4a8e133a3b35321b9cc7d87022cc4b91723 (diff)
syz-gce: add autonomous GCE runner
It is meant to download new kernel images from GCS, update and rebuild syzkaller and restart syz-manager. Work in progress...
Diffstat (limited to 'gce')
-rw-r--r--gce/gce.go95
1 files changed, 71 insertions, 24 deletions
diff --git a/gce/gce.go b/gce/gce.go
index 2ae3aae37..a6cf7a5e0 100644
--- a/gce/gce.go
+++ b/gce/gce.go
@@ -3,6 +3,12 @@
// Package gce provides wrappers around Google Compute Engine (GCE) APIs.
// It is assumed that the program itself also runs on GCE as APIs operate on the current project/zone.
+//
+// See https://cloud.google.com/compute/docs for details.
+// In particular, API reference:
+// https://cloud.google.com/compute/docs/reference/latest
+// and Go API wrappers:
+// https://godoc.org/google.golang.org/api/compute/v0.beta
package gce
import (
@@ -84,24 +90,6 @@ func NewContext() (*Context, error) {
return ctx, nil
}
-func (ctx *Context) getMeta(path string) (string, error) {
- req, err := http.NewRequest("GET", "http://metadata.google.internal/computeMetadata/v1/"+path, nil)
- if err != nil {
- return "", err
- }
- req.Header.Add("Metadata-Flavor", "Google")
- resp, err := http.DefaultClient.Do(req)
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
- return string(body), nil
-}
-
func (ctx *Context) CreateInstance(name, machineType, image, sshkey string) (string, error) {
prefix := "https://www.googleapis.com/compute/v1/projects/" + ctx.ProjectID
instance := &compute.Instance{
@@ -148,7 +136,7 @@ func (ctx *Context) CreateInstance(name, machineType, image, sshkey string) (str
if err != nil {
return "", fmt.Errorf("failed to create instance: %v", err)
}
- if err := ctx.waitForCompletion("create", op.Name, false); err != nil {
+ if err := ctx.waitForCompletion("zone", "create image", op.Name, false); err != nil {
return "", err
}
@@ -175,24 +163,65 @@ func (ctx *Context) CreateInstance(name, machineType, image, sshkey string) (str
func (ctx *Context) DeleteInstance(name string) error {
<-ctx.apiRateGate
op, err := ctx.computeService.Instances.Delete(ctx.ProjectID, ctx.ZoneID, name).Do()
- apiErr, ok := err.(*googleapi.Error)
- if ok && apiErr.Code == 404 {
+ if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
return nil
}
if err != nil {
return fmt.Errorf("failed to delete instance: %v", err)
}
- if err := ctx.waitForCompletion("delete", op.Name, true); err != nil {
+ if err := ctx.waitForCompletion("zone", "delete image", op.Name, true); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (ctx *Context) CreateImage(imageName, gcsFile string) error {
+ image := &compute.Image{
+ Name: imageName,
+ RawDisk: &compute.ImageRawDisk{
+ Source: "https://storage.googleapis.com/" + gcsFile,
+ },
+ }
+ <-ctx.apiRateGate
+ op, err := ctx.computeService.Images.Insert(ctx.ProjectID, image).Do()
+ if err != nil {
+ return fmt.Errorf("failed to create image: %v", err)
+ }
+ if err := ctx.waitForCompletion("global", "create image", op.Name, false); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (ctx *Context) DeleteImage(imageName string) error {
+ <-ctx.apiRateGate
+ op, err := ctx.computeService.Images.Delete(ctx.ProjectID, imageName).Do()
+ if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
+ return nil
+ }
+ if err != nil {
+ return fmt.Errorf("failed to delete image: %v", err)
+ }
+ if err := ctx.waitForCompletion("global", "delete image", op.Name, true); err != nil {
return err
}
return nil
}
-func (ctx *Context) waitForCompletion(desc, opName string, ignoreNotFound bool) error {
+func (ctx *Context) waitForCompletion(typ, desc, opName string, ignoreNotFound bool) error {
for {
time.Sleep(2 * time.Second)
<-ctx.apiRateGate
- op, err := ctx.computeService.ZoneOperations.Get(ctx.ProjectID, ctx.ZoneID, opName).Do()
+ var err error
+ var op *compute.Operation
+ switch typ {
+ case "global":
+ op, err = ctx.computeService.GlobalOperations.Get(ctx.ProjectID, opName).Do()
+ case "zone":
+ op, err = ctx.computeService.ZoneOperations.Get(ctx.ProjectID, ctx.ZoneID, opName).Do()
+ default:
+ panic("unknown operation type: " + typ)
+ }
if err != nil {
return fmt.Errorf("failed to get %v operation %v: %v", desc, opName, err)
}
@@ -216,3 +245,21 @@ func (ctx *Context) waitForCompletion(desc, opName string, ignoreNotFound bool)
}
}
}
+
+func (ctx *Context) getMeta(path string) (string, error) {
+ req, err := http.NewRequest("GET", "http://metadata.google.internal/computeMetadata/v1/"+path, nil)
+ if err != nil {
+ return "", err
+ }
+ req.Header.Add("Metadata-Flavor", "Google")
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return "", err
+ }
+ return string(body), nil
+}