From 4b3a4d8eae7cf709186193bdafbd00c7b32dbf85 Mon Sep 17 00:00:00 2001 From: Christy Norman Date: Fri, 4 Feb 2022 17:55:10 -0600 Subject: [PATCH] Add IBM Power VS: tfvars For more background on IPI on Power VS, refer to the enhancement proposal here: openshift/enhancements#736 Older discussions on some of the code here can be found in #5224 Signed-off-by: Christy Norman --- pkg/asset/cluster/tfvars.go | 48 ++++++++++++ pkg/asset/installconfig/powervs/client.go | 9 ++- pkg/asset/installconfig/powervs/session.go | 3 - pkg/asset/rhcos/image.go | 15 ++++ pkg/terraform/stages/platform/stages.go | 4 + pkg/terraform/stages/powervs/stages.go | 17 +++++ pkg/tfvars/powervs/powervs.go | 87 ++++++++++++++++++++++ 7 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 pkg/terraform/stages/powervs/stages.go create mode 100644 pkg/tfvars/powervs/powervs.go diff --git a/pkg/asset/cluster/tfvars.go b/pkg/asset/cluster/tfvars.go index 8140328db6b..16277c2a355 100644 --- a/pkg/asset/cluster/tfvars.go +++ b/pkg/asset/cluster/tfvars.go @@ -13,6 +13,7 @@ import ( ibmcloudprovider "github.com/openshift/cluster-api-provider-ibmcloud/pkg/apis/ibmcloudprovider/v1beta1" libvirtprovider "github.com/openshift/cluster-api-provider-libvirt/pkg/apis/libvirtproviderconfig/v1beta1" ovirtprovider "github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1" + powervsprovider "github.com/openshift/machine-api-provider-powervs/pkg/apis/powervsprovider/v1alpha1" "github.com/pkg/errors" "github.com/sirupsen/logrus" awsprovider "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsprovider/v1beta1" @@ -45,6 +46,7 @@ import ( libvirttfvars "github.com/openshift/installer/pkg/tfvars/libvirt" openstacktfvars "github.com/openshift/installer/pkg/tfvars/openstack" ovirttfvars "github.com/openshift/installer/pkg/tfvars/ovirt" + powervstfvars "github.com/openshift/installer/pkg/tfvars/powervs" vspheretfvars "github.com/openshift/installer/pkg/tfvars/vsphere" "github.com/openshift/installer/pkg/types" "github.com/openshift/installer/pkg/types/alibabacloud" @@ -57,6 +59,7 @@ import ( "github.com/openshift/installer/pkg/types/none" "github.com/openshift/installer/pkg/types/openstack" "github.com/openshift/installer/pkg/types/ovirt" + "github.com/openshift/installer/pkg/types/powervs" "github.com/openshift/installer/pkg/types/vsphere" ) @@ -673,6 +676,51 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { Filename: TfPlatformVarsFileName, Data: data, }) + case powervs.Name: + client, err := installConfig.PowerVS.Client() + if err != nil { + return err + } + + masters, err := mastersAsset.Machines() + if err != nil { + return err + } + + // Get CISInstanceCRN from InstallConfig metadata + crn, err := installConfig.PowerVS.CISInstanceCRN(ctx) + if err != nil { + return err + } + + masterConfigs := make([]*powervsprovider.PowerVSMachineProviderConfig, len(masters)) + for i, m := range masters { + masterConfigs[i] = m.Spec.ProviderSpec.Value.Object.(*powervsprovider.PowerVSMachineProviderConfig) + } + + data, err = powervstfvars.TFVars( + powervstfvars.TFVarsSources{ + MasterConfigs: masterConfigs, + Region: installConfig.Config.Platform.PowerVS.Region, + Zone: installConfig.Config.Platform.PowerVS.Zone, + APIKey: client.APIKey, + SSHKey: installConfig.Config.SSHKey, + PowerVSResourceGroup: installConfig.Config.PowerVS.PowerVSResourceGroup, + ImageBucketFileName: string(*rhcosImage), + NetworkName: installConfig.Config.PowerVS.PVSNetworkName, + CISInstanceCRN: crn, + VPCSubnetName: installConfig.Config.PowerVS.Subnets[0], + VPCName: installConfig.Config.PowerVS.VPC, + }, + ) + if err != nil { + return errors.Wrapf(err, "failed to get %s Terraform variables", platform) + } + t.FileList = append(t.FileList, &asset.File{ + Filename: TfPlatformVarsFileName, + Data: data, + }) + case vsphere.Name: controlPlanes, err := mastersAsset.Machines() if err != nil { diff --git a/pkg/asset/installconfig/powervs/client.go b/pkg/asset/installconfig/powervs/client.go index ec4094d4bcf..d02afca735e 100644 --- a/pkg/asset/installconfig/powervs/client.go +++ b/pkg/asset/installconfig/powervs/client.go @@ -3,7 +3,6 @@ package powervs import ( "context" "fmt" - "os" "time" "github.com/IBM/go-sdk-core/v5/core" @@ -55,9 +54,13 @@ type DNSZoneResponse struct { // NewClient initializes a client with a session. func NewClient() (*Client, error) { - apiKey := os.Getenv("IC_API_KEY") + ssn, err := GetSession() + if err != nil { + return nil, err + } + client := &Client{ - APIKey: apiKey, + APIKey: ssn.APIKey, } if err := client.loadSDKServices(); err != nil { diff --git a/pkg/asset/installconfig/powervs/session.go b/pkg/asset/installconfig/powervs/session.go index 885f8e46db5..af7389093ca 100644 --- a/pkg/asset/installconfig/powervs/session.go +++ b/pkg/asset/installconfig/powervs/session.go @@ -75,9 +75,6 @@ func getPISession() (*ibmpisession.IBMPISession, string, error) { return nil, "", err } - // This is needed by ibmcloud code to gather DNS information later. - os.Setenv("IC_API_KEY", pisv.APIKey) - piOpts := ibmpisession.IBMPIOptions{ Authenticator: &core.IamAuthenticator{ ApiKey: pisv.APIKey, diff --git a/pkg/asset/rhcos/image.go b/pkg/asset/rhcos/image.go index dcd6e02c218..c4682912df0 100644 --- a/pkg/asset/rhcos/image.go +++ b/pkg/asset/rhcos/image.go @@ -25,6 +25,7 @@ import ( "github.com/openshift/installer/pkg/types/nutanix" "github.com/openshift/installer/pkg/types/openstack" "github.com/openshift/installer/pkg/types/ovirt" + "github.com/openshift/installer/pkg/types/powervs" "github.com/openshift/installer/pkg/types/vsphere" ) @@ -163,6 +164,20 @@ func osImage(config *types.InstallConfig) (string, error) { return "", err } return osimage, nil + case powervs.Name: + // Check for image URL override + if config.Platform.PowerVS.ClusterOSImage != "" { + return config.Platform.PowerVS.ClusterOSImage, nil + } + + if streamArch.Images.PowerVS != nil { + vpcRegion := powervs.Regions[config.Platform.PowerVS.Region].VPCRegion + img := streamArch.Images.PowerVS.Regions[vpcRegion] + logrus.Debug("Power VS using image ", img.Object) + return img.Object, nil + } + + return "", fmt.Errorf("%s: No Power VS build found", st.FormatPrefix(archName)) case none.Name: return "", nil case nutanix.Name: diff --git a/pkg/terraform/stages/platform/stages.go b/pkg/terraform/stages/platform/stages.go index 136f9326603..794f8a45430 100644 --- a/pkg/terraform/stages/platform/stages.go +++ b/pkg/terraform/stages/platform/stages.go @@ -13,6 +13,7 @@ import ( "github.com/openshift/installer/pkg/terraform/stages/libvirt" "github.com/openshift/installer/pkg/terraform/stages/openstack" "github.com/openshift/installer/pkg/terraform/stages/ovirt" + "github.com/openshift/installer/pkg/terraform/stages/powervs" "github.com/openshift/installer/pkg/terraform/stages/vsphere" alibabacloudtypes "github.com/openshift/installer/pkg/types/alibabacloud" awstypes "github.com/openshift/installer/pkg/types/aws" @@ -23,6 +24,7 @@ import ( libvirttypes "github.com/openshift/installer/pkg/types/libvirt" openstacktypes "github.com/openshift/installer/pkg/types/openstack" ovirttypes "github.com/openshift/installer/pkg/types/ovirt" + powervstypes "github.com/openshift/installer/pkg/types/powervs" vspheretypes "github.com/openshift/installer/pkg/types/vsphere" ) @@ -45,6 +47,8 @@ func StagesForPlatform(platform string) []terraform.Stage { return ibmcloud.PlatformStages case libvirttypes.Name: return libvirt.PlatformStages + case powervstypes.Name: + return powervs.PlatformStages case openstacktypes.Name: return openstack.PlatformStages case ovirttypes.Name: diff --git a/pkg/terraform/stages/powervs/stages.go b/pkg/terraform/stages/powervs/stages.go new file mode 100644 index 00000000000..6c86ce04caa --- /dev/null +++ b/pkg/terraform/stages/powervs/stages.go @@ -0,0 +1,17 @@ +package powervs + +import ( + "github.com/openshift/installer/pkg/terraform" + "github.com/openshift/installer/pkg/terraform/providers" + "github.com/openshift/installer/pkg/terraform/stages" +) + +// PlatformStages are the stages to run to provision the infrastructure in PowerVS. +var PlatformStages = []terraform.Stage{ + stages.NewStage("powervs", + "cluster", + []providers.Provider{providers.IBM, providers.Ignition}), + stages.NewStage("powervs", + "post-install", + []providers.Provider{providers.IBM}), +} diff --git a/pkg/tfvars/powervs/powervs.go b/pkg/tfvars/powervs/powervs.go new file mode 100644 index 00000000000..e5791b6f9bb --- /dev/null +++ b/pkg/tfvars/powervs/powervs.go @@ -0,0 +1,87 @@ +// Package powervs contains Power Virtual Servers-specific Terraform-variable logic. +package powervs + +import ( + "encoding/json" + "fmt" + "math/rand" + "time" + + "github.com/openshift/installer/pkg/types/powervs" + "github.com/openshift/machine-api-provider-powervs/pkg/apis/powervsprovider/v1alpha1" +) + +type config struct { + ServiceInstanceID string `json:"powervs_cloud_instance_id"` + APIKey string `json:"powervs_api_key"` + SSHKey string `json:"powervs_ssh_key"` + PowerVSRegion string `json:"powervs_region"` + PowerVSZone string `json:"powervs_zone"` + VPCRegion string `json:"powervs_vpc_region"` + VPCZone string `json:"powervs_vpc_zone"` + PowerVSResourceGroup string `json:"powervs_resource_group"` + CISInstanceCRN string `json:"powervs_cis_crn"` + ImageBucketFileName string `json:"powervs_image_bucket_file_name"` + NetworkName string `json:"powervs_network_name"` + VPCName string `json:"powervs_vpc_name"` + VPCSubnetName string `json:"powervs_vpc_subnet_name"` + BootstrapMemory string `json:"powervs_bootstrap_memory"` + BootstrapProcessors string `json:"powervs_bootstrap_processors"` + MasterMemory string `json:"powervs_master_memory"` + MasterProcessors string `json:"powervs_master_processors"` + ProcType string `json:"powervs_proc_type"` + SysType string `json:"powervs_sys_type"` +} + +// TFVarsSources contains the parameters to be converted into Terraform variables +type TFVarsSources struct { + MasterConfigs []*v1alpha1.PowerVSMachineProviderConfig + APIKey string + SSHKey string + Region string + Zone string + ImageBucketFileName string + NetworkName string + PowerVSResourceGroup string + CISInstanceCRN string + VPCName string + VPCSubnetName string +} + +// TFVars generates Power VS-specific Terraform variables launching the cluster. +func TFVars(sources TFVarsSources) ([]byte, error) { + masterConfig := sources.MasterConfigs[0] + // TODO(mjturek): Allow user to specify vpcRegion in install config like we're doing for vpcZone + vpcRegion := powervs.Regions[sources.Region].VPCRegion + + // Randomly select a zone in the VPC region. + // @TODO: Align this with a region later. + rand.Seed(time.Now().UnixNano()) + // All supported Regions are MZRs and have Zones named "region-[1-3]" + vpcZone := fmt.Sprintf("%s-%d", vpcRegion, rand.Intn(3)) + + //@TODO: Add resource group to platform + cfg := &config{ + ServiceInstanceID: masterConfig.ServiceInstanceID, + APIKey: sources.APIKey, + SSHKey: sources.SSHKey, + PowerVSRegion: sources.Region, + PowerVSZone: sources.Zone, + VPCRegion: vpcRegion, + VPCZone: vpcZone, + PowerVSResourceGroup: sources.PowerVSResourceGroup, + CISInstanceCRN: sources.CISInstanceCRN, + ImageBucketFileName: sources.ImageBucketFileName, + NetworkName: *masterConfig.Network.Name, + VPCName: sources.VPCName, + VPCSubnetName: sources.VPCSubnetName, + BootstrapMemory: masterConfig.Memory, + BootstrapProcessors: masterConfig.Processors, + MasterMemory: masterConfig.Memory, + MasterProcessors: masterConfig.Processors, + ProcType: masterConfig.ProcType, + SysType: masterConfig.SysType, + } + + return json.MarshalIndent(cfg, "", " ") +}