From 8fc735142ef6543455de1361522e88a222b368da Mon Sep 17 00:00:00 2001 From: Hiro Miyamoto Date: Tue, 29 Oct 2024 20:29:11 -0400 Subject: [PATCH] Creates VPEs as needed for Disconnected install Signed-off-by: Hiro Miyamoto --- pkg/asset/cluster/metadata.go | 6 +- pkg/asset/cluster/powervs/powervs.go | 20 ++- pkg/asset/installconfig/powervs/client.go | 73 +++++++++++ pkg/asset/installconfig/powervs/metadata.go | 124 ++++++++++++++++++ .../powervs/mock/powervsclient_generated.go | 15 +++ pkg/asset/installconfig/powervs/session.go | 19 ++- pkg/asset/manifests/cloudproviderconfig.go | 7 +- pkg/asset/manifests/infrastructure.go | 13 ++ .../manifests/powervs/cloudproviderconfig.go | 18 +++ pkg/clusterapi/system.go | 4 +- .../powervs/clusterapi/powervs.go | 13 ++ 11 files changed, 299 insertions(+), 13 deletions(-) diff --git a/pkg/asset/cluster/metadata.go b/pkg/asset/cluster/metadata.go index 47905dfc29b..b37f5835869 100644 --- a/pkg/asset/cluster/metadata.go +++ b/pkg/asset/cluster/metadata.go @@ -3,6 +3,7 @@ package cluster import ( "context" "encoding/json" + "fmt" "github.com/pkg/errors" @@ -97,7 +98,10 @@ func (m *Metadata) Generate(_ context.Context, parents asset.Parents) (err error case vspheretypes.Name: metadata.ClusterPlatformMetadata.VSphere = vsphere.Metadata(installConfig.Config) case powervstypes.Name: - metadata.ClusterPlatformMetadata.PowerVS = powervs.Metadata(installConfig.Config, installConfig.PowerVS) + metadata.ClusterPlatformMetadata.PowerVS, err = powervs.Metadata(installConfig.Config, installConfig.PowerVS) + if err != nil { + return fmt.Errorf("failed to initialize PowerVS: %w", err) + } case externaltypes.Name, nonetypes.Name: case nutanixtypes.Name: metadata.ClusterPlatformMetadata.Nutanix = nutanix.Metadata(installConfig.Config) diff --git a/pkg/asset/cluster/powervs/powervs.go b/pkg/asset/cluster/powervs/powervs.go index fbf7575e4ed..637b1d4bc09 100644 --- a/pkg/asset/cluster/powervs/powervs.go +++ b/pkg/asset/cluster/powervs/powervs.go @@ -10,10 +10,24 @@ import ( ) // Metadata converts an install configuration to PowerVS metadata. -func Metadata(config *types.InstallConfig, meta *icpowervs.Metadata) *powervs.Metadata { +func Metadata(config *types.InstallConfig, meta *icpowervs.Metadata) (*powervs.Metadata, error) { cisCRN, _ := meta.CISInstanceCRN(context.TODO()) dnsCRN, _ := meta.DNSInstanceCRN(context.TODO()) + overrides := config.Platform.PowerVS.ServiceEndpoints + if config.Publish == types.InternalPublishingStrategy && + (len(config.ImageDigestSources) > 0 || len(config.DeprecatedImageContentSources) > 0) { + cosRegion, err := powervs.COSRegionForPowerVSRegion(config.PowerVS.Region) + if err != nil { + return nil, err + } + vpcRegion, err := powervs.VPCRegionForPowerVSRegion(config.PowerVS.Region) + if err != nil { + return nil, err + } + overrides = meta.SetDefaultPrivateServiceEndpoints(context.TODO(), overrides, cosRegion, vpcRegion) + } + return &powervs.Metadata{ BaseDomain: config.BaseDomain, PowerVSResourceGroup: config.Platform.PowerVS.PowerVSResourceGroup, @@ -23,7 +37,7 @@ func Metadata(config *types.InstallConfig, meta *icpowervs.Metadata) *powervs.Me VPCRegion: config.Platform.PowerVS.VPCRegion, Zone: config.Platform.PowerVS.Zone, ServiceInstanceGUID: config.Platform.PowerVS.ServiceInstanceGUID, - ServiceEndpoints: config.Platform.PowerVS.ServiceEndpoints, + ServiceEndpoints: overrides, TransitGatewayName: config.Platform.PowerVS.TGName, - } + }, nil } diff --git a/pkg/asset/installconfig/powervs/client.go b/pkg/asset/installconfig/powervs/client.go index e08d9410aa0..adfdc492a9b 100644 --- a/pkg/asset/installconfig/powervs/client.go +++ b/pkg/asset/installconfig/powervs/client.go @@ -85,6 +85,9 @@ type API interface { // Load Balancer AddIPToLoadBalancerPool(ctx context.Context, lbID string, poolName string, port int64, ip string) error + + // Virtual Private Endpoint Gateway + CreateVirtualPrivateEndpointGateway(ctx context.Context, name string, vpcID string, subnetID string, rgID string, targetCRN string) (*vpcv1.EndpointGateway, error) } // Client makes calls to the PowerVS API. @@ -1459,3 +1462,73 @@ func (c *Client) AddIPToLoadBalancerPool(ctx context.Context, lbID string, poolN return true, nil }) } + +// CreateVirtualPrivateEndpointGateway creates a VPE gateway with given target resource type and CRN. +func (c *Client) CreateVirtualPrivateEndpointGateway(ctx context.Context, name string, vpcID string, subnetID string, rgID string, targetCRN string) (*vpcv1.EndpointGateway, error) { + var ( + resp *core.DetailedResponse + err error + ok bool + egs *vpcv1.EndpointGatewayCollection + egRef *vpcv1.EndpointGatewayTarget + idIntf *vpcv1.VPCIdentityByID + target *vpcv1.EndpointGatewayTargetPrototypeEndpointGatewayTargetResourceTypeProviderCloudServicePrototype + rgIntf *vpcv1.ResourceGroupIdentityByID + ipIntf *vpcv1.EndpointGatewayReservedIPReservedIPIdentityByID + ) + + listOpts := c.vpcAPI.NewListEndpointGatewaysOptions() + listOpts.SetVPCID(vpcID) + egs, _, err = c.vpcAPI.ListEndpointGateways(listOpts) + if err != nil { + return nil, err + } + + for _, eg := range egs.EndpointGateways { + egRef, ok = eg.Target.(*vpcv1.EndpointGatewayTarget) + if !ok { + return nil, fmt.Errorf("invalid target inside returned EndpointGateway: %v", eg.Target) + } + if *egRef.CRN == targetCRN { + return &eg, nil + } + } + + target, err = c.vpcAPI.NewEndpointGatewayTargetPrototypeEndpointGatewayTargetResourceTypeProviderCloudServicePrototype(targetCRN, vpcv1.EndpointGatewayTargetPrototypeResourceTypeProviderCloudServiceConst) + if err != nil { + return nil, err + } + idIntf, err = c.vpcAPI.NewVPCIdentityByID(vpcID) + if err != nil { + return nil, err + } + createOpts := c.vpcAPI.NewCreateEndpointGatewayOptions(target, idIntf) + createOpts.SetName(name) + createOpts.SetAllowDnsResolutionBinding(true) + rgIntf, err = c.vpcAPI.NewResourceGroupIdentityByID(rgID) + if err != nil { + return nil, err + } + createOpts.SetResourceGroup(rgIntf) + ipName := fmt.Sprintf("%s-ip", name) + createIPOpts := c.vpcAPI.NewCreateSubnetReservedIPOptions(subnetID) + createIPOpts.SetName(ipName) + createIPOpts.SetSubnetID(subnetID) + reservedIP, _, err := c.vpcAPI.CreateSubnetReservedIPWithContext(ctx, createIPOpts) + if err != nil { + return nil, err + } + ipIntf, err = c.vpcAPI.NewEndpointGatewayReservedIPReservedIPIdentityByID(*reservedIP.ID) + if err != nil { + return nil, err + } + ips := []vpcv1.EndpointGatewayReservedIPIntf{ipIntf} + createOpts.SetIps(ips) + + eg, resp, err := c.vpcAPI.CreateEndpointGatewayWithContext(ctx, createOpts) + if err != nil { + logrus.Debugf("CreateEndpointGatewayWithContext returned %v", resp) + return nil, err + } + return eg, nil +} diff --git a/pkg/asset/installconfig/powervs/metadata.go b/pkg/asset/installconfig/powervs/metadata.go index ee48512cb6c..70df86adfc7 100644 --- a/pkg/asset/installconfig/powervs/metadata.go +++ b/pkg/asset/installconfig/powervs/metadata.go @@ -9,11 +9,21 @@ import ( "github.com/IBM-Cloud/bluemix-go/crn" "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/wait" + configv1 "github.com/openshift/api/config/v1" "github.com/openshift/installer/pkg/types" ) +const ( + cosCrnTempl = "crn:v1:bluemix:public:cloud-object-storage:global:::endpoint:s3.direct.%s.cloud-object-storage.appdomain.cloud" + dnsCrn = "crn:v1:bluemix:public:dns-svcs:global::::" + iamCrn = "crn:v1:bluemix:public:iam-svcs:global:::endpoint:private.iam.cloud.ibm.com" + rcCrn = "crn:v1:bluemix:public:resource-controller:global:::endpoint:private.resource-controller.cloud.ibm.com" + vpcCrnTempl = "crn:v1:bluemix:public:is:%s:::endpoint:%s.private.iaas.cloud.ibm.com" +) + //go:generate mockgen -source=./metadata.go -destination=./mock/powervsmetadata_generated.go -package=mock // MetadataAPI represents functions that eventually call out to the API @@ -491,3 +501,117 @@ func leftInContext(ctx context.Context) time.Duration { return time.Until(deadline) } + +// SetDefaultPrivateServiceEndpoints sets service endpoint overrides as needed for Disconnected install. +func (m *Metadata) SetDefaultPrivateServiceEndpoints(ctx context.Context, overrides []configv1.PowerVSServiceEndpoint, cosRegion string, vpcRegion string) []configv1.PowerVSServiceEndpoint { + overrides = addOverride(overrides, "COS", fmt.Sprintf("https://s3.direct.%s.cloud-object-storage.appdomain.cloud", cosRegion)) + overrides = addOverride(overrides, "DNSServices", "https://api.private.dns-svcs.cloud.ibm.com") + overrides = addOverride(overrides, "IAM", "https://private.iam.cloud.ibm.com") + overrides = addOverride(overrides, "Power", fmt.Sprintf("https://private.%s.power-iaas.cloud.ibm.com", vpcRegion)) + overrides = addOverride(overrides, "ResourceController", "https://private.resource-controller.cloud.ibm.com") + overrides = addOverride(overrides, "VPC", fmt.Sprintf("https://%s.private.iaas.cloud.ibm.com", vpcRegion)) + return overrides +} + +func addOverride(overrides []configv1.PowerVSServiceEndpoint, name string, url string) []configv1.PowerVSServiceEndpoint { + found := false + for _, service := range overrides { + if service.Name == name { + found = true + break + } + } + if !found { + return append(overrides, configv1.PowerVSServiceEndpoint{Name: name, URL: url}) + } + return overrides +} + +// CreateVirtualPrivateEndpointGateways checks and creates necessary VPEs in given target VPC for Disconnected install. +func (m *Metadata) CreateVirtualPrivateEndpointGateways(ctx context.Context, infraID string, region string, vpcID string, subnetID string, groupID string, endpointOverrides []configv1.PowerVSServiceEndpoint) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + client, err := m.client() + if err != nil { + return err + } + + endpoint, err := m.fetchEndpointOverride(endpointOverrides, "IAM") + if err != nil { + return fmt.Errorf("failed to fetch endpoint override found for IAM: %w", err) + } + if endpoint == "" { + name := fmt.Sprintf("%s-vpe-iam", infraID) + logrus.Debugf("InfraReady: Ensuring VPE gateway for IAM %v", iamCrn) + _, err = client.CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, groupID, iamCrn) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + + endpoint, err = m.fetchEndpointOverride(endpointOverrides, "COS") + if err != nil { + return fmt.Errorf("failed to fetch endpoint override found for COS: %w", err) + } + if endpoint == "" { + name := fmt.Sprintf("%s-vpe-cos", infraID) + cosCrn := fmt.Sprintf(cosCrnTempl, region) + logrus.Debugf("InfraReady: Ensuring VPE gateway for COS %v", cosCrn) + _, err = client.CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, groupID, cosCrn) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + + endpoint, err = m.fetchEndpointOverride(endpointOverrides, "DNSServices") + if err != nil { + return fmt.Errorf("failed to fetch endpoint override found for DNS: %w", err) + } + if endpoint == "" { + name := fmt.Sprintf("%s-vpe-dns", infraID) + logrus.Debugf("InfraReady: Ensuring VPE gateway for DNS services %v", dnsCrn) + _, err = client.CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, groupID, dnsCrn) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + + endpoint, err = m.fetchEndpointOverride(endpointOverrides, string(configv1.IBMCloudServiceResourceController)) + if err != nil { + return fmt.Errorf("failed to fetch endpoint override found for RC: %w", err) + } + if endpoint == "" { + name := fmt.Sprintf("%s-vpe-rc", infraID) + logrus.Debugf("InfraReady: Ensuring VPE gateway for RC %v", rcCrn) + _, err = client.CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, groupID, rcCrn) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + + endpoint, err = m.fetchEndpointOverride(endpointOverrides, string(configv1.IBMCloudServiceVPC)) + if err != nil { + return fmt.Errorf("failed to fetch endpoint override found for VPC: %w", err) + } + if endpoint == "" { + name := fmt.Sprintf("%s-vpe-vpc", infraID) + vpcCrn := fmt.Sprintf(vpcCrnTempl, region, region) + logrus.Debugf("InfraReady: Ensuring VPE gateway for VPC %v", vpcCrn) + _, err = client.CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, groupID, vpcCrn) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + + return nil +} + +func (m *Metadata) fetchEndpointOverride(overrides []configv1.PowerVSServiceEndpoint, svcID string) (string, error) { + for _, endpoint := range overrides { + if endpoint.Name == svcID { + return endpoint.URL, nil + } + } + return "", nil +} diff --git a/pkg/asset/installconfig/powervs/mock/powervsclient_generated.go b/pkg/asset/installconfig/powervs/mock/powervsclient_generated.go index 8a83435b412..d6020d42316 100644 --- a/pkg/asset/installconfig/powervs/mock/powervsclient_generated.go +++ b/pkg/asset/installconfig/powervs/mock/powervsclient_generated.go @@ -125,6 +125,21 @@ func (mr *MockAPIMockRecorder) CreateSSHKey(ctx, serviceInstance, zone, sshKeyNa return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSSHKey", reflect.TypeOf((*MockAPI)(nil).CreateSSHKey), ctx, serviceInstance, zone, sshKeyName, sshKey) } +// CreateVirtualPrivateEndpointGateway mocks base method. +func (m *MockAPI) CreateVirtualPrivateEndpointGateway(ctx context.Context, name, vpcID, subnetID, rgID, targetCRN string) (*vpcv1.EndpointGateway, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateVirtualPrivateEndpointGateway", ctx, name, vpcID, subnetID, rgID, targetCRN) + ret0, _ := ret[0].(*vpcv1.EndpointGateway) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateVirtualPrivateEndpointGateway indicates an expected call of CreateVirtualPrivateEndpointGateway. +func (mr *MockAPIMockRecorder) CreateVirtualPrivateEndpointGateway(ctx, name, vpcID, subnetID, rgID, targetCRN interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateVirtualPrivateEndpointGateway", reflect.TypeOf((*MockAPI)(nil).CreateVirtualPrivateEndpointGateway), ctx, name, vpcID, subnetID, rgID, targetCRN) +} + // EnableDNSCustomResolver mocks base method. func (m *MockAPI) EnableDNSCustomResolver(ctx context.Context, dnsID, resolverID string) (*dnssvcsv1.CustomResolver, error) { m.ctrl.T.Helper() diff --git a/pkg/asset/installconfig/powervs/session.go b/pkg/asset/installconfig/powervs/session.go index b0d886966a2..9f61b6741f1 100644 --- a/pkg/asset/installconfig/powervs/session.go +++ b/pkg/asset/installconfig/powervs/session.go @@ -15,7 +15,6 @@ import ( "github.com/IBM/go-sdk-core/v5/core" "github.com/form3tech-oss/jwt-go" "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/util/sets" "github.com/openshift/installer/pkg/types/powervs" ) @@ -427,14 +426,22 @@ func getEnv(envs []string) string { return "" } -// FilterServiceEndpoints drops service endpoint overrides that are not supported by PowerVS CAPI provider. -func (c *BxClient) FilterServiceEndpoints(cfg *powervs.Metadata) []string { - capiSupported := sets.New("cos", "powervs", "rc", "rm", "vpc") // see serviceIDs array definition in https://github.com/kubernetes-sigs/cluster-api-provider-ibmcloud/blob/main/pkg/endpoints/endpoints.go +// MapServiceEndpointsForCAPI drops service endpoint overrides that are not supported by PowerVS CAPI provider, while also translating service names. +func (c *BxClient) MapServiceEndpointsForCAPI(cfg *powervs.Metadata) []string { + // Keys are what installer recognizes from install-config.yaml, and values are what PowerVS CAPI accepts + // Should contain only mapping for serviceIDs from https://github.com/kubernetes-sigs/cluster-api-provider-ibmcloud/blob/main/pkg/endpoints/endpoints.go + capiSupported := map[string]string{ + "COS": "cos", + "Power": "powervs", + "ResourceController": "", // FIXME CAPI recognizes "rc," but crashes if passed in... + "ResourceManager": "rm", + "VPC": "vpc", + } overrides := make([]string, 0, len(cfg.ServiceEndpoints)) // CAPI expects name=url pairs of service endpoints for _, endpoint := range cfg.ServiceEndpoints { - if capiSupported.Has(endpoint.Name) { - overrides = append(overrides, fmt.Sprintf("%s=%s", endpoint.Name, endpoint.URL)) + if capiName, ok := capiSupported[endpoint.Name]; ok && capiName != "" { + overrides = append(overrides, fmt.Sprintf("%s=%s", capiSupported[endpoint.Name], endpoint.URL)) } else { logrus.Infof("Unsupported service endpoint skipped: %s", endpoint.Name) } diff --git a/pkg/asset/manifests/cloudproviderconfig.go b/pkg/asset/manifests/cloudproviderconfig.go index 062f283e0d0..6f33e5d6c37 100644 --- a/pkg/asset/manifests/cloudproviderconfig.go +++ b/pkg/asset/manifests/cloudproviderconfig.go @@ -300,6 +300,11 @@ func (cpc *CloudProviderConfig) Generate(ctx context.Context, dependencies asset serviceGUID = installConfig.Config.PowerVS.ServiceInstanceGUID } + cosRegion, err := powervstypes.COSRegionForPowerVSRegion(installConfig.Config.PowerVS.Region) + if err != nil { + return err + } + powervsConfig, err := powervsmanifests.CloudProviderConfig( clusterID.InfraID, accountID, @@ -311,7 +316,7 @@ func (cpc *CloudProviderConfig) Generate(ctx context.Context, dependencies asset serviceName, installConfig.Config.PowerVS.Region, installConfig.Config.PowerVS.Zone, - installConfig.Config.PowerVS.ServiceEndpoints, + installConfig.PowerVS.SetDefaultPrivateServiceEndpoints(ctx, installConfig.Config.PowerVS.ServiceEndpoints, cosRegion, vpcRegion), ) if err != nil { return errors.Wrap(err, "could not create cloud provider config") diff --git a/pkg/asset/manifests/infrastructure.go b/pkg/asset/manifests/infrastructure.go index c9e18f82d16..3d01b4ac7ea 100644 --- a/pkg/asset/manifests/infrastructure.go +++ b/pkg/asset/manifests/infrastructure.go @@ -311,6 +311,19 @@ func (i *Infrastructure) Generate(ctx context.Context, dependencies asset.Parent URL: service.URL, }) } + if installConfig.Config.Publish == types.InternalPublishingStrategy && + (len(installConfig.Config.ImageDigestSources) > 0 || len(installConfig.Config.DeprecatedImageContentSources) > 0) { + piRegion := installConfig.Config.PowerVS.Region + vpcRegion, err := powervs.VPCRegionForPowerVSRegion(piRegion) + if err != nil { + return fmt.Errorf("failed to determine VPC region: %w", err) + } + cosRegion, err := powervs.COSRegionForPowerVSRegion(piRegion) + if err != nil { + return fmt.Errorf("failed to determine COS region: %w", err) + } + config.Spec.PlatformSpec.PowerVS.ServiceEndpoints = installConfig.PowerVS.SetDefaultPrivateServiceEndpoints(ctx, config.Spec.PlatformSpec.PowerVS.ServiceEndpoints, cosRegion, vpcRegion) + } config.Status.PlatformStatus.PowerVS = &configv1.PowerVSPlatformStatus{ Region: installConfig.Config.Platform.PowerVS.Region, Zone: installConfig.Config.Platform.PowerVS.Zone, diff --git a/pkg/asset/manifests/powervs/cloudproviderconfig.go b/pkg/asset/manifests/powervs/cloudproviderconfig.go index 5cc20937f76..33b576637ad 100644 --- a/pkg/asset/manifests/powervs/cloudproviderconfig.go +++ b/pkg/asset/manifests/powervs/cloudproviderconfig.go @@ -35,20 +35,32 @@ type provider struct { G2VPCName string `gcfg:"g2VpcName"` G2WorkerServiceAccountID string `gcfg:"g2workerServiceAccountID"` G2VPCSubnetNames string `gcfg:"g2VpcSubnetNames"` + G2EndpointOverride string `gcfg:"g2EndpointOverride"` PowerVSCloudInstanceID string `gcfg:"powerVSCloudInstanceID"` PowerVSCloudInstanceName string `gcfg:"powerVSCloudInstanceName"` PowerVSRegion string `gcfg:"powerVSRegion"` PowerVSZone string `gcfg:"powerVSZone"` IamEndpointOverride string `gcfg:"iamEndpointOverride"` + PowerVSEndpointOverride string `gcfg:"powerVSEndpointOverride"` + RcEndpointOverride string `gcfg:"rcEndpointOverride"` } // CloudProviderConfig generates the cloud provider config for the IBM Power VS platform. func CloudProviderConfig(infraID string, accountID string, vpcName string, region string, resourceGroupName string, subnets []string, cloudInstGUID string, cloudInstName string, pvsRegion string, pvsZone string, endpointOverrides []configv1.PowerVSServiceEndpoint) (string, error) { iamEndpointOverride := "" + rcEndpointOverride := "" + powerVSEndpointOverride := "" + vpcEndpointOverride := "" for _, endpoint := range endpointOverrides { switch endpoint.Name { case string(configv1.IBMCloudServiceIAM): iamEndpointOverride = endpoint.URL + case string(configv1.IBMCloudServiceResourceController): + rcEndpointOverride = endpoint.URL + case "Power": // FIXME configv1.IBMCloudServicePower? + powerVSEndpointOverride = endpoint.URL + case string(configv1.IBMCloudServiceVPC): + vpcEndpointOverride = endpoint.URL default: logrus.Debugf("Ignoring unrecognized endpoint override for cloud provider config: %s", endpoint.Name) } @@ -74,7 +86,10 @@ func CloudProviderConfig(infraID string, accountID string, vpcName string, regio PowerVSCloudInstanceName: cloudInstName, PowerVSRegion: pvsRegion, PowerVSZone: pvsZone, + G2EndpointOverride: vpcEndpointOverride, IamEndpointOverride: iamEndpointOverride, + PowerVSEndpointOverride: powerVSEndpointOverride, + RcEndpointOverride: rcEndpointOverride, }, } buf := &bytes.Buffer{} @@ -103,5 +118,8 @@ powerVSCloudInstanceID = {{.Provider.PowerVSCloudInstanceID}} powerVSCloudInstanceName = {{.Provider.PowerVSCloudInstanceName}} powerVSRegion = {{.Provider.PowerVSRegion}} powerVSZone = {{.Provider.PowerVSZone}} +g2EndpointOverride = {{.Provider.G2EndpointOverride}} iamEndpointOverride = {{.Provider.IamEndpointOverride}} +powerVSEndpointOverride = {{.Provider.PowerVSEndpointOverride}} +rcEndpointOverride = {{.Provider.RcEndpointOverride}} ` diff --git a/pkg/clusterapi/system.go b/pkg/clusterapi/system.go index be29f2f8927..8bd1b6e5e09 100644 --- a/pkg/clusterapi/system.go +++ b/pkg/clusterapi/system.go @@ -344,8 +344,8 @@ func (c *system) Run(ctx context.Context) error { //nolint:gocyclo "LOGLEVEL": "2", }, ) - if cfg := metadata.PowerVS; cfg != nil && len(cfg.ServiceEndpoints) > 0 { - overrides := bxClient.FilterServiceEndpoints(cfg) + if cfg := metadata.PowerVS; cfg != nil { + overrides := bxClient.MapServiceEndpointsForCAPI(cfg) if len(overrides) > 0 { controller.Args = append(controller.Args, fmt.Sprintf("--service-endpoint=%s:%s", cfg.Region, strings.Join(overrides, ","))) } diff --git a/pkg/infrastructure/powervs/clusterapi/powervs.go b/pkg/infrastructure/powervs/clusterapi/powervs.go index db131b9fbf4..be09b086f79 100644 --- a/pkg/infrastructure/powervs/clusterapi/powervs.go +++ b/pkg/infrastructure/powervs/clusterapi/powervs.go @@ -163,6 +163,19 @@ func (p Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput) if err != nil { return fmt.Errorf("failed to add ping security group rule: %w", err) } + + if in.InstallConfig.Config.Publish == types.InternalPublishingStrategy && + (len(in.InstallConfig.Config.ImageDigestSources) > 0 || len(in.InstallConfig.Config.DeprecatedImageContentSources) > 0) { + vpcID := *powerVSCluster.Status.VPC.ID + logrus.Debugf("InfraReady: Ensuring necessary VPE gateways are in place in VPC %v", vpcID) + groupID := *powerVSCluster.Status.ResourceGroup.ID + subnetID := *powerVSCluster.Status.VPCSubnet[*powerVSCluster.Spec.VPCSubnets[1].Name].ID + err = in.InstallConfig.PowerVS.CreateVirtualPrivateEndpointGateways(ctx, in.InfraID, vpcRegion, vpcID, subnetID, groupID, in.InstallConfig.Config.PowerVS.ServiceEndpoints) + if err != nil { + return fmt.Errorf("failed to create VPE: %w", err) + } + } + return nil }