diff --git a/data/data/gcp/main.tf b/data/data/gcp/main.tf index 3a787c60fca..c590e39ec87 100644 --- a/data/data/gcp/main.tf +++ b/data/data/gcp/main.tf @@ -4,6 +4,8 @@ locals { master_subnet_cidr = cidrsubnet(var.machine_v4_cidrs[0], 3, 0) #master subnet is a smaller subnet within the vnet. i.e from /21 to /24 worker_subnet_cidr = cidrsubnet(var.machine_v4_cidrs[0], 3, 1) #worker subnet is a smaller subnet within the vnet. i.e from /21 to /24 public_endpoints = var.gcp_publish_strategy == "External" ? true : false + + gcp_image = var.gcp_preexisting_image ? var.gcp_image : google_compute_image.cluster[0].self_link } provider "google" { @@ -17,7 +19,7 @@ module "bootstrap" { bootstrap_enabled = var.gcp_bootstrap_enabled - image = google_compute_image.cluster.self_link + image = local.gcp_image machine_type = var.gcp_bootstrap_instance_type cluster_id = var.cluster_id ignition = var.ignition_bootstrap @@ -36,7 +38,7 @@ module "bootstrap" { module "master" { source = "./master" - image = google_compute_image.cluster.self_link + image = local.gcp_image instance_count = var.master_count machine_type = var.gcp_master_instance_type cluster_id = var.cluster_id @@ -91,6 +93,8 @@ module "dns" { } resource "google_compute_image" "cluster" { + count = var.gcp_preexisting_image ? 0 : 1 + name = "${var.cluster_id}-rhcos-image" # See https://github.com/openshift/installer/issues/2546 diff --git a/data/data/gcp/variables-gcp.tf b/data/data/gcp/variables-gcp.tf index 45262bf25bf..435f05aa54e 100644 --- a/data/data/gcp/variables-gcp.tf +++ b/data/data/gcp/variables-gcp.tf @@ -48,7 +48,18 @@ variable "gcp_master_instance_type" { variable "gcp_image_uri" { type = string - description = "Image for all nodes." + description = "URL to Raw Image for all nodes. This is used in case a new image needs to be generated for the nodes." +} + +variable "gcp_image" { + type = string + description = "URL to the Image for all nodes." +} + +variable "gcp_preexisting_image" { + type = bool + default = true + description = "Specifies whether an existing GCP Image should be used or a new one created for installation" } variable "gcp_master_root_volume_type" { diff --git a/pkg/asset/cluster/tfvars.go b/pkg/asset/cluster/tfvars.go index 7590a76324b..328625aa204 100644 --- a/pkg/asset/cluster/tfvars.go +++ b/pkg/asset/cluster/tfvars.go @@ -31,6 +31,7 @@ import ( "github.com/openshift/installer/pkg/asset/machines" "github.com/openshift/installer/pkg/asset/openshiftinstall" "github.com/openshift/installer/pkg/asset/rhcos" + rhcospkg "github.com/openshift/installer/pkg/rhcos" "github.com/openshift/installer/pkg/tfvars" awstfvars "github.com/openshift/installer/pkg/tfvars/aws" azuretfvars "github.com/openshift/installer/pkg/tfvars/azure" @@ -327,12 +328,17 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { publicZoneName = publicZone.Name } preexistingnetwork := installConfig.Config.GCP.Network != "" + + imageRaw, err := rhcospkg.GCPRaw(ctx, installConfig.Config.ControlPlane.Architecture) + if err != nil { + return errors.Wrap(err, "failed to find Raw GCP image URL") + } data, err := gcptfvars.TFVars( gcptfvars.TFVarsSources{ Auth: auth, MasterConfigs: masterConfigs, WorkerConfigs: workerConfigs, - ImageURI: string(*rhcosImage), + ImageURI: imageRaw, ImageLicenses: installConfig.Config.GCP.Licenses, PublicZoneName: publicZoneName, PublishStrategy: installConfig.Config.Publish, diff --git a/pkg/asset/machines/gcp/machines.go b/pkg/asset/machines/gcp/machines.go index 50d86a85515..c82f80f7db2 100644 --- a/pkg/asset/machines/gcp/machines.go +++ b/pkg/asset/machines/gcp/machines.go @@ -69,7 +69,9 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine func provider(clusterID string, platform *gcp.Platform, mpool *gcp.MachinePool, osImage string, azIdx int, role, userDataSecret string) (*gcpprovider.GCPMachineProviderSpec, error) { az := mpool.Zones[azIdx] - + if len(platform.Licenses) > 0 { + osImage = fmt.Sprintf("%s-rhcos-image", clusterID) + } network, subnetwork, err := getNetworks(platform, clusterID, role) if err != nil { return nil, err @@ -87,7 +89,7 @@ func provider(clusterID string, platform *gcp.Platform, mpool *gcp.MachinePool, Boot: true, SizeGb: mpool.OSDisk.DiskSizeGB, Type: mpool.OSDisk.DiskType, - Image: fmt.Sprintf("%s-rhcos-image", clusterID), + Image: osImage, }}, NetworkInterfaces: []*gcpprovider.GCPNetworkInterface{{ Network: network, diff --git a/pkg/rhcos/builds.go b/pkg/rhcos/builds.go index d2d423c82d8..76d0b64415f 100644 --- a/pkg/rhcos/builds.go +++ b/pkg/rhcos/builds.go @@ -26,8 +26,9 @@ type metadata struct { URL string `json:"url"` } GCP struct { - Image string `json:"image"` - URL string `json:"url"` + Image string `json:"image"` + Project string `json:"project"` + URL string `json:"url"` } BaseURI string `json:"baseURI"` Images struct { diff --git a/pkg/rhcos/gcp.go b/pkg/rhcos/gcp.go index e1dc4df66cb..96dbbf27833 100644 --- a/pkg/rhcos/gcp.go +++ b/pkg/rhcos/gcp.go @@ -2,23 +2,29 @@ package rhcos import ( "context" + "fmt" "github.com/pkg/errors" "github.com/openshift/installer/pkg/types" ) -// GCP fetches the URL of the public GCP storage bucket containing the RHCOS image +// GCP fetches the URL of the public RHCOS image func GCP(ctx context.Context, arch types.Architecture) (string, error) { meta, err := fetchRHCOSBuild(ctx, arch) if err != nil { return "", errors.Wrap(err, "failed to fetch RHCOS metadata") } - url := meta.GCP.URL - if url == "" { - return "", errors.New("no RHCOS GCP URL found") + return fmt.Sprintf("projects/%s/global/images/%s", meta.GCP.Project, meta.GCP.Image), nil +} + +// GCPRaw fetches the URL of the public GCP storage bucket containing the RHCOS image +func GCPRaw(ctx context.Context, arch types.Architecture) (string, error) { + meta, err := fetchRHCOSBuild(ctx, arch) + if err != nil { + return "", errors.Wrap(err, "failed to fetch RHCOS metadata") } - return url, nil + return meta.GCP.URL, nil } diff --git a/pkg/tfvars/gcp/gcp.go b/pkg/tfvars/gcp/gcp.go index 01bd7c55413..db97edd837b 100644 --- a/pkg/tfvars/gcp/gcp.go +++ b/pkg/tfvars/gcp/gcp.go @@ -21,6 +21,8 @@ type config struct { MasterInstanceType string `json:"gcp_master_instance_type,omitempty"` MasterAvailabilityZones []string `json:"gcp_master_availability_zones"` ImageURI string `json:"gcp_image_uri,omitempty"` + Image string `json:"gcp_image,omitempty"` + PreexistingImage bool `json:"gcp_preexisting_image"` ImageLicenses []string `json:"gcp_image_licenses,omitempty"` VolumeType string `json:"gcp_master_root_volume_type"` VolumeSize int64 `json:"gcp_master_root_volume_size"` @@ -36,7 +38,7 @@ type config struct { type TFVarsSources struct { Auth Auth ImageURI string - ImageLicenses []string `json:"gcp_image_licenses,omitempty"` + ImageLicenses []string MasterConfigs []*gcpprovider.GCPMachineProviderSpec WorkerConfigs []*gcpprovider.GCPMachineProviderSpec PublicZoneName string @@ -52,6 +54,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) { for i, c := range sources.MasterConfigs { masterAvailabilityZones[i] = c.Zone } + cfg := &config{ Auth: sources.Auth, Region: masterConfig.Region, @@ -61,6 +64,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) { VolumeType: masterConfig.Disks[0].Type, VolumeSize: masterConfig.Disks[0].SizeGb, ImageURI: sources.ImageURI, + Image: masterConfig.Disks[0].Image, ImageLicenses: sources.ImageLicenses, PublicZoneName: sources.PublicZoneName, PublishStrategy: string(sources.PublishStrategy), @@ -69,6 +73,10 @@ func TFVars(sources TFVarsSources) ([]byte, error) { ComputeSubnet: workerConfig.NetworkInterfaces[0].Subnetwork, PreexistingNetwork: sources.PreexistingNetwork, } + cfg.PreexistingImage = true + if len(sources.ImageLicenses) > 0 { + cfg.PreexistingImage = false + } return json.MarshalIndent(cfg, "", " ") }