From 3dd45d41aac21b43a918c4a1d462947c59f1711f Mon Sep 17 00:00:00 2001
From: Dave Tucker
Date: Wed, 26 Jul 2017 20:53:50 +0100
Subject: [PATCH] linuxkit: Better GCP disk handling
This commit allows the GCP backend to use the familiar `-disk` behaviour
that the local hypervisors use. The `file` attribute is used as the disk
name in GCP. The size is converted to GB and is always > 1GB.
This has the benefit of allowing multiple disks to be used with GCP
instances.
Signed-off-by: Dave Tucker
---
src/cmd/linuxkit/gcp.go | 57 +++++++++++++++++++++++--------------
src/cmd/linuxkit/run_gcp.go | 24 ++++++++--------
src/cmd/linuxkit/util.go | 12 ++++++++
3 files changed, 60 insertions(+), 33 deletions(-)
diff --git a/src/cmd/linuxkit/gcp.go b/src/cmd/linuxkit/gcp.go
index e7f4472a4..82895d49c 100644
--- a/src/cmd/linuxkit/gcp.go
+++ b/src/cmd/linuxkit/gcp.go
@@ -178,7 +178,7 @@ func (g GCPClient) DeleteImage(name string) error {
}
// CreateInstance creates and starts an instance on GCP
-func (g GCPClient) CreateInstance(name, image, zone, machineType string, diskSize int, replace bool) error {
+func (g GCPClient) CreateInstance(name, image, zone, machineType string, disks Disks, replace bool) error {
if replace {
if err := g.DeleteInstance(name, zone, true); err != nil {
return err
@@ -197,32 +197,47 @@ func (g GCPClient) CreateInstance(name, image, zone, machineType string, diskSiz
sshKey := new(string)
*sshKey = fmt.Sprintf("moby:%s moby", string(ssh.MarshalAuthorizedKey(k)))
- diskName := name + "-systemdisk"
- diskOp, err := g.compute.Disks.Insert(g.projectName, zone, &compute.Disk{Name: diskName, SizeGb: int64(diskSize)}).Do()
- if err != nil {
- return err
+ instanceDisks := []*compute.AttachedDisk{
+ {
+ AutoDelete: true,
+ Boot: true,
+ InitializeParams: &compute.AttachedDiskInitializeParams{
+ SourceImage: fmt.Sprintf("global/images/%s", image),
+ },
+ },
}
- if err := g.pollZoneOperationStatus(diskOp.Name, zone); err != nil {
- return err
+
+ for i, disk := range disks {
+ var diskName string
+ if disk.Path != "" {
+ diskName = disk.Path
+ } else {
+ diskName = fmt.Sprintf("%s-disk-%d", name, i)
+ }
+ var diskSizeGb int64
+ if disk.Size == 0 {
+ diskSizeGb = int64(1)
+ } else {
+ diskSizeGb = int64(convertMBtoGB(disk.Size))
+ }
+ diskOp, err := g.compute.Disks.Insert(g.projectName, zone, &compute.Disk{Name: diskName, SizeGb: diskSizeGb}).Do()
+ if err != nil {
+ return err
+ }
+ if err := g.pollZoneOperationStatus(diskOp.Name, zone); err != nil {
+ return err
+ }
+ instanceDisks = append(instanceDisks, &compute.AttachedDisk{
+ AutoDelete: true,
+ Boot: false,
+ Source: fmt.Sprintf("zones/%s/disks/%s", zone, diskName),
+ })
}
instanceObj := &compute.Instance{
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", zone, machineType),
Name: name,
- Disks: []*compute.AttachedDisk{
- {
- AutoDelete: true,
- Boot: true,
- InitializeParams: &compute.AttachedDiskInitializeParams{
- SourceImage: fmt.Sprintf("global/images/%s", image),
- },
- },
- {
- AutoDelete: true,
- Boot: false,
- Source: fmt.Sprintf("zones/%s/disks/%s", zone, diskName),
- },
- },
+ Disks: instanceDisks,
NetworkInterfaces: []*compute.NetworkInterface{
{
Network: "global/networks/default",
diff --git a/src/cmd/linuxkit/run_gcp.go b/src/cmd/linuxkit/run_gcp.go
index d6f63d5b3..ba9faed7d 100644
--- a/src/cmd/linuxkit/run_gcp.go
+++ b/src/cmd/linuxkit/run_gcp.go
@@ -14,15 +14,14 @@ const (
defaultMachine = "g1-small"
defaultDiskSize = 1
// Environment variables. Some are non-standard
- zoneVar = "CLOUDSDK_COMPUTE_ZONE"
- machineVar = "CLOUDSDK_COMPUTE_MACHINE" // non-standard
- keysVar = "CLOUDSDK_COMPUTE_KEYS" // non-standard
- projectVar = "CLOUDSDK_CORE_PROJECT"
- bucketVar = "CLOUDSDK_IMAGE_BUCKET" // non-standard
- familyVar = "CLOUDSDK_IMAGE_FAMILY" // non-standard
- publicVar = "CLOUDSDK_IMAGE_PUBLIC" // non-standard
- nameVar = "CLOUDSDK_IMAGE_NAME" // non-standard
- diskSizeVar = "CLOUDSDK_DISK_SIZE" // non-standard
+ zoneVar = "CLOUDSDK_COMPUTE_ZONE"
+ machineVar = "CLOUDSDK_COMPUTE_MACHINE" // non-standard
+ keysVar = "CLOUDSDK_COMPUTE_KEYS" // non-standard
+ projectVar = "CLOUDSDK_CORE_PROJECT"
+ bucketVar = "CLOUDSDK_IMAGE_BUCKET" // non-standard
+ familyVar = "CLOUDSDK_IMAGE_FAMILY" // non-standard
+ publicVar = "CLOUDSDK_IMAGE_PUBLIC" // non-standard
+ nameVar = "CLOUDSDK_IMAGE_NAME" // non-standard
)
// Process the run arguments and execute run
@@ -41,7 +40,9 @@ func runGcp(args []string) {
machineFlag := flags.String("machine", defaultMachine, "GCP Machine Type")
keysFlag := flags.String("keys", "", "Path to Service Account JSON key file")
projectFlag := flags.String("project", "", "GCP Project Name")
- diskSizeFlag := flags.Int("disk-size", 0, "Size of system disk in GB")
+ var disks Disks
+ flags.Var(&disks, "disk", "Disk config, may be repeated. [file=]diskName[,size=1G]")
+
skipCleanup := flags.Bool("skip-cleanup", false, "Don't remove images or VMs")
if err := flags.Parse(args); err != nil {
@@ -60,14 +61,13 @@ func runGcp(args []string) {
machine := getStringValue(machineVar, *machineFlag, defaultMachine)
keys := getStringValue(keysVar, *keysFlag, "")
project := getStringValue(projectVar, *projectFlag, "")
- diskSize := getIntValue(diskSizeVar, *diskSizeFlag, defaultDiskSize)
client, err := NewGCPClient(keys, project)
if err != nil {
log.Fatalf("Unable to connect to GCP")
}
- if err = client.CreateInstance(name, name, zone, machine, diskSize, true); err != nil {
+ if err = client.CreateInstance(name, name, zone, machine, disks, true); err != nil {
log.Fatal(err)
}
diff --git a/src/cmd/linuxkit/util.go b/src/cmd/linuxkit/util.go
index f7a8b1faf..93bd2ff75 100644
--- a/src/cmd/linuxkit/util.go
+++ b/src/cmd/linuxkit/util.go
@@ -135,6 +135,18 @@ func getDiskSizeMB(s string) (int, error) {
return 1024 * i, nil
}
+func convertMBtoGB(i int) int {
+ if i < 1024 {
+ return 1
+ }
+
+ if i%1024 == 0 {
+ return i / 1024
+ }
+
+ return (i + (1024 - i%1024)) / 1024
+}
+
// DiskConfig is the config for a disk
type DiskConfig struct {
Path string