diff --git a/tools/baseimage/cmd/create_gce_base_image/main.go b/tools/baseimage/cmd/create_gce_base_image/main.go index c2d9db77455..4af8b7cd100 100644 --- a/tools/baseimage/cmd/create_gce_base_image/main.go +++ b/tools/baseimage/cmd/create_gce_base_image/main.go @@ -65,6 +65,25 @@ func main() { log.Fatal("usage: `-image-name` must not be empty") } + h, err := gce.NewGceHelper(project, zone) + if err != nil { + log.Fatal(err) + } + + if srcExists, err := h.ImageExists(sourceImageProject, sourceImage); err != nil || !srcExists { + if err != nil { + log.Fatal(err) + } + log.Fatalf("source image %q does not exist in project %q", sourceImage, sourceImageProject) + } + + if exists, err := h.ImageExists(project, imageName); err != nil || exists { + if err != nil { + log.Fatal(err) + } + log.Fatalf("image %q already exists in project %q", imageName, project) + } + buildImageOpts := gce.BuildImageOpts{ Arch: arch.GceArch(), SourceImageProject: sourceImageProject, @@ -81,10 +100,6 @@ func main() { }, } - h, err := gce.NewGceHelper(project, zone) - if err != nil { - log.Fatal(err) - } if err := h.BuildImage(project, zone, buildImageOpts); err != nil { log.Fatal(err) } diff --git a/tools/baseimage/cmd/create_gce_fixed_kernel/main.go b/tools/baseimage/cmd/create_gce_fixed_kernel/main.go index 9a554520393..b1e0ae3f7eb 100644 --- a/tools/baseimage/cmd/create_gce_fixed_kernel/main.go +++ b/tools/baseimage/cmd/create_gce_fixed_kernel/main.go @@ -90,10 +90,30 @@ func main() { slices.Collect(maps.Keys(sourceImageMap[arch.GceArch()]))) } + h, err := gce.NewGceHelper(project, zone) + if err != nil { + log.Fatal(err) + } + + sourceImage := sourceImageMap[arch.GceArch()][debianVersion] + if srcExists, err := h.ImageExists(debianSourceImageProject, sourceImage); err != nil || !srcExists { + if err != nil { + log.Fatal(err) + } + log.Fatalf("source image %q does not exist in project %q", sourceImage, debianSourceImageProject) + } + + if exists, err := h.ImageExists(project, imageName); err != nil || exists { + if err != nil { + log.Fatal(err) + } + log.Fatalf("image %q already exists in project %q", imageName, project) + } + buildImageOpts := gce.BuildImageOpts{ Arch: arch.GceArch(), SourceImageProject: debianSourceImageProject, - SourceImage: sourceImageMap[arch.GceArch()][debianVersion], + SourceImage: sourceImage, ImageName: imageName, ModifyFunc: func(project, zone, insName string) error { if err := gce.UploadBashScript(project, zone, insName, "install_kernel_main.sh", scripts.InstallKernelMain); err != nil { @@ -103,10 +123,6 @@ func main() { }, } - h, err := gce.NewGceHelper(project, zone) - if err != nil { - log.Fatal(err) - } if err := h.BuildImage(project, zone, buildImageOpts); err != nil { log.Fatal(err) } diff --git a/tools/baseimage/pkg/gce/gce.go b/tools/baseimage/pkg/gce/gce.go index cd26abed16d..6881a67a1c0 100644 --- a/tools/baseimage/pkg/gce/gce.go +++ b/tools/baseimage/pkg/gce/gce.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "log" + "net/http" "os/exec" "path" "strings" @@ -26,6 +27,7 @@ import ( "github.com/google/android-cuttlefish/tools/baseimage/pkg/gce/scripts" "google.golang.org/api/compute/v1" + "google.golang.org/api/googleapi" ) type Arch int @@ -246,6 +248,30 @@ func (h *GceHelper) CreateImage(ins, disk, name string) error { return h.waitForGlobalOperation(op) } +func (h *GceHelper) ImageExists(project, name string) (bool, error) { + _, err := h.Service.Images.Get(project, name).Do() + if err != nil { + var apiErr *googleapi.Error + if errors.As(err, &apiErr) && apiErr.Code == http.StatusNotFound { + return false, nil + } + return false, err + } + return true, nil +} + +func (h *GceHelper) DiskExists(project, zone, name string) (bool, error) { + _, err := h.Service.Disks.Get(project, zone, name).Do() + if err != nil { + var apiErr *googleapi.Error + if errors.As(err, &apiErr) && apiErr.Code == http.StatusNotFound { + return false, nil + } + return false, err + } + return true, nil +} + type BuildImageOpts struct { Arch Arch SourceImageProject string @@ -260,6 +286,12 @@ const BuildImageMountPoint = "/mnt/image" func (h *GceHelper) BuildImage(project, zone string, opts BuildImageOpts) error { insName := opts.ImageName attachedDiskName := fmt.Sprintf("%s-attached-disk", insName) + if diskExists, err := h.DiskExists(project, zone, attachedDiskName); err != nil || diskExists { + if err != nil { + return fmt.Errorf("failed to check if disk %q exists: %w", attachedDiskName, err) + } + return fmt.Errorf("disk %q already exists in project %q zone %q", attachedDiskName, project, zone) + } log.Println("creating instance...") inst, err := h.CreateInstance(insName, opts.Arch)