diff --git a/pkg/asset/cluster/cluster.go b/pkg/asset/cluster/cluster.go index ab6acc0c699..671eaf33244 100644 --- a/pkg/asset/cluster/cluster.go +++ b/pkg/asset/cluster/cluster.go @@ -12,6 +12,7 @@ import ( "github.com/openshift/installer/pkg/asset" "github.com/openshift/installer/pkg/asset/cluster/aws" + "github.com/openshift/installer/pkg/asset/cluster/vsphere" "github.com/openshift/installer/pkg/asset/installconfig" "github.com/openshift/installer/pkg/asset/password" "github.com/openshift/installer/pkg/terraform" @@ -77,6 +78,11 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { return err } } + if installConfig.Config.Platform.VSphere != nil { + if err := vsphere.PreTerraform(context.TODO(), clusterID.InfraID, installConfig); err != nil { + return err + } + } stateFile, err := terraform.Apply(tmpDir, installConfig.Config.Platform.Name(), extraArgs...) if err != nil { diff --git a/pkg/asset/cluster/tfvars.go b/pkg/asset/cluster/tfvars.go index 65b94273b24..5eee85a86b4 100644 --- a/pkg/asset/cluster/tfvars.go +++ b/pkg/asset/cluster/tfvars.go @@ -425,17 +425,20 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { for i, c := range controlPlanes { controlPlaneConfigs[i] = c.Spec.ProviderSpec.Value.Object.(*vsphereprovider.VSphereMachineProviderSpec) } - data, err = vspheretfvars.TFVars( + data, cachedImage, err := vspheretfvars.TFVars( vspheretfvars.TFVarsSources{ ControlPlaneConfigs: controlPlaneConfigs, Username: installConfig.Config.VSphere.Username, Password: installConfig.Config.VSphere.Password, Cluster: installConfig.Config.VSphere.Cluster, + ImageURI: string(*rhcosImage), }, ) if err != nil { return errors.Wrapf(err, "failed to get %s Terraform variables", platform) } + installConfig.Config.VSphere.ClusterOSImage = cachedImage + t.FileList = append(t.FileList, &asset.File{ Filename: fmt.Sprintf(TfPlatformVarsFileName, platform), Data: data, diff --git a/pkg/asset/cluster/vsphere/vsphere.go b/pkg/asset/cluster/vsphere/vsphere.go index e1d45fe2c5a..0d7761021af 100644 --- a/pkg/asset/cluster/vsphere/vsphere.go +++ b/pkg/asset/cluster/vsphere/vsphere.go @@ -1,6 +1,9 @@ package vsphere import ( + "context" + + "github.com/openshift/installer/pkg/asset/installconfig" "github.com/openshift/installer/pkg/types" "github.com/openshift/installer/pkg/types/vsphere" ) @@ -13,3 +16,10 @@ func Metadata(config *types.InstallConfig) *vsphere.Metadata { Password: config.VSphere.Password, } } + +// PreTerraform performs any infrastructure initialization which must +// happen before Terraform creates the remaining infrastructure. +func PreTerraform(ctx context.Context, infraID string, installConfig *installconfig.InstallConfig) error { + // TODO: create VM Template using cachedImage + return nil +} diff --git a/pkg/asset/rhcos/image.go b/pkg/asset/rhcos/image.go index 2e87d1cb1a8..7a92c841a10 100644 --- a/pkg/asset/rhcos/image.go +++ b/pkg/asset/rhcos/image.go @@ -95,8 +95,15 @@ func osImage(config *types.InstallConfig) (string, error) { // because this contains the necessary ironic config drive // ignition support, which isn't enabled in the UPI BM images osimage, err = rhcos.OpenStack(ctx, arch) - case none.Name, vsphere.Name: + case vsphere.Name: + // Check for RHCOS image URL override + if config.Platform.VSphere.ClusterOSImage != "" { + osimage = config.Platform.VSphere.ClusterOSImage + break + } + osimage, err = rhcos.VMware(ctx, arch) + case none.Name: default: return "", errors.New("invalid Platform") } diff --git a/pkg/rhcos/builds.go b/pkg/rhcos/builds.go index eaaf2a2558b..d2d423c82d8 100644 --- a/pkg/rhcos/builds.go +++ b/pkg/rhcos/builds.go @@ -41,6 +41,10 @@ type metadata struct { SHA256 string `json:"sha256"` UncompressedSHA256 string `json:"uncompressed-sha256"` } `json:"openstack"` + VMware struct { + Path string `json:"path"` + SHA256 string `json:"sha256"` + } `json:"vmware"` } `json:"images"` OSTreeVersion string `json:"ostree-version"` } diff --git a/pkg/rhcos/vmware.go b/pkg/rhcos/vmware.go new file mode 100644 index 00000000000..889b016f40a --- /dev/null +++ b/pkg/rhcos/vmware.go @@ -0,0 +1,44 @@ +package rhcos + +import ( + "context" + "net/url" + + "github.com/pkg/errors" + + "github.com/openshift/installer/pkg/types" +) + +// VMware fetches the URL of the Red Hat Enterprise Linux CoreOS release. +func VMware(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") + } + + base, err := url.Parse(meta.BaseURI) + if err != nil { + return "", err + } + + image, err := url.Parse(meta.Images.VMware.Path) + if err != nil { + return "", err + } + + baseURL := base.ResolveReference(image).String() + + // TODO: Get Uncompressed SHA256 into rhcos.json + // Attach sha256 checksum to the URL. Always provide the + // uncompressed SHA256; the cache will take care of + // uncompressing before checksumming. + //baseURL += "?sha256=" + meta.Images.VMware.UncompressedSHA256 + + // Check that we have generated a valid URL + _, err = url.ParseRequestURI(baseURL) + if err != nil { + return "", err + } + + return baseURL, nil +} diff --git a/pkg/tfvars/vsphere/vsphere.go b/pkg/tfvars/vsphere/vsphere.go index 9a152418269..b146ab01bbe 100644 --- a/pkg/tfvars/vsphere/vsphere.go +++ b/pkg/tfvars/vsphere/vsphere.go @@ -3,6 +3,9 @@ package vsphere import ( "encoding/json" + "github.com/pkg/errors" + + "github.com/openshift/installer/pkg/tfvars/internal/cache" vsphereapis "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1" ) @@ -28,12 +31,18 @@ type TFVarsSources struct { Username string Password string Cluster string + ImageURI string } //TFVars generate vSphere-specific Terraform variables -func TFVars(sources TFVarsSources) ([]byte, error) { +func TFVars(sources TFVarsSources) ([]byte, string, error) { controlPlaneConfig := sources.ControlPlaneConfigs[0] + cachedImage, err := cache.DownloadImageFile(sources.ImageURI) + if err != nil { + return nil, "", errors.Wrap(err, "failed to use cached vsphere image") + } + cfg := &config{ VSphereURL: controlPlaneConfig.Workspace.Server, VSphereUsername: sources.Username, @@ -50,5 +59,10 @@ func TFVars(sources TFVarsSources) ([]byte, error) { Template: controlPlaneConfig.Template, } - return json.MarshalIndent(cfg, "", " ") + cfgFormatted, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return nil, "", err + } + + return cfgFormatted, cachedImage, nil }