diff --git a/api/v1beta2/ibmpowervscluster_types.go b/api/v1beta2/ibmpowervscluster_types.go index 65efbf5cd..bbee8922e 100644 --- a/api/v1beta2/ibmpowervscluster_types.go +++ b/api/v1beta2/ibmpowervscluster_types.go @@ -251,6 +251,11 @@ type TransitGateway struct { // id of resource. // +optional ID *string `json:"id,omitempty"` + // globalRouting indicates whether to set global routing true or not while creating the transit gateway. + // set this field to true only when PowerVS and VPC are from different regions, if they are same it's suggested to use local routing by setting the field to false. + // when the field is omitted, based on PowerVS region (region associated with IBMPowerVSCluster.Spec.Zone) and VPC region(IBMPowerVSCluster.Spec.VPC.Region) system will decide whether to enable globalRouting or not. + // +optional + GlobalRouting *bool `json:"globalRouting,omitempty"` } // VPCResourceReference is a reference to a specific VPC resource by ID or Name diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 20a61a028..5171d98b6 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -1518,6 +1518,11 @@ func (in *TransitGateway) DeepCopyInto(out *TransitGateway) { *out = new(string) **out = **in } + if in.GlobalRouting != nil { + in, out := &in.GlobalRouting, &out.GlobalRouting + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TransitGateway. diff --git a/cloud/scope/powervs_cluster.go b/cloud/scope/powervs_cluster.go index b1a1160b0..e4932d789 100644 --- a/cloud/scope/powervs_cluster.go +++ b/cloud/scope/powervs_cluster.go @@ -1334,16 +1334,25 @@ func (s *PowerVSClusterScope) createTransitGateway() (*string, error) { return nil, fmt.Errorf("error getting resource group id for resource group %v, id is empty", s.ResourceGroup()) } - vpcRegion := s.getVPCRegion() - if vpcRegion == nil { - return nil, fmt.Errorf("failed to get vpc region") + location, globalRouting := s.getTransitGatewayLocationAndRouting() + if location == nil { + return nil, fmt.Errorf("failed to get transit gateway location") + } + + // throw error when user tries to use local routing where global routing is required. + if s.IBMPowerVSCluster.Spec.TransitGateway.GlobalRouting != nil && !*s.IBMPowerVSCluster.Spec.TransitGateway.GlobalRouting && *globalRouting { + return nil, fmt.Errorf("failed to use local routing for transit gateway since powervs and vpc region used requires global routing") + } + // setting global routing to true when it is set by user. + if s.IBMPowerVSCluster.Spec.TransitGateway.GlobalRouting != nil && *s.IBMPowerVSCluster.Spec.TransitGateway.GlobalRouting { + globalRouting = ptr.To(true) } tgName := s.GetServiceName(infrav1beta2.ResourceTypeTransitGateway) tg, _, err := s.TransitGatewayClient.CreateTransitGateway(&tgapiv1.CreateTransitGatewayOptions{ - Location: vpcRegion, + Location: location, Name: tgName, - Global: ptr.To(true), + Global: globalRouting, ResourceGroup: &tgapiv1.ResourceGroupIdentity{ID: ptr.To(resourceGroupID)}, }) if err != nil { @@ -1744,24 +1753,29 @@ func (s *PowerVSClusterScope) fetchResourceGroupID() (string, error) { return "", err } -// getVPCRegion returns region associated with VPC zone. -func (s *PowerVSClusterScope) getVPCRegion() *string { - if s.IBMPowerVSCluster.Spec.VPC != nil { - return s.IBMPowerVSCluster.Spec.VPC.Region - } - // if vpc region is not set try to fetch corresponding region from power vs zone +// getTransitGatewayLocationAndRouting returns appropriate location and routing suitable for transit gateway. +// routing indicates whether to enable global routing on transit gateway or not. +// returns true when powervs and vpc region are not common otherwise false. +func (s *PowerVSClusterScope) getTransitGatewayLocationAndRouting() (*string, *bool) { zone := s.Zone() if zone == nil { s.Info("powervs zone is not set") - return nil + return nil, nil } region := endpoints.ConstructRegionFromZone(*zone) - vpcRegion, err := genUtil.VPCRegionForPowerVSRegion(region) + + if s.VPC() != nil { + routing := genUtil.IsGlobalRoutingRequiredForTG(region, *s.IBMPowerVSCluster.Spec.VPC.Region) + return s.IBMPowerVSCluster.Spec.VPC.Region, &routing + } + location, err := genUtil.VPCRegionForPowerVSRegion(region) if err != nil { s.Error(err, fmt.Sprintf("failed to fetch vpc region associated with powervs region %s", region)) - return nil + return nil, nil } - return &vpcRegion + + routing := genUtil.IsGlobalRoutingRequiredForTG(region, *s.IBMPowerVSCluster.Spec.VPC.Region) + return &location, &routing } // fetchVPCCRN returns VPC CRN. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclusters.yaml index ad94420e4..36ad2d754 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclusters.yaml @@ -396,6 +396,12 @@ spec: when TransitGateway.ID is set, its expected that there exist a TransitGateway with ID or else system will give error. when TransitGateway.Name is set, system will first check for TransitGateway with Name, if not exist system will create new TransitGateway. properties: + globalRouting: + description: |- + globalRouting indicates whether to set global routing true or not while creating the transit gateway. + set this field to true only when PowerVS and VPC are from different regions, if they are same it's suggested to use local routing by setting the field to false. + when the field is omitted, based on PowerVS region (region associated with IBMPowerVSCluster.Spec.Zone) and VPC region(IBMPowerVSCluster.Spec.VPC.Region) system will decide whether to enable globalRouting or not. + type: boolean id: description: id of resource. type: string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclustertemplates.yaml index fa43d3519..8d6198996 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsclustertemplates.yaml @@ -427,6 +427,12 @@ spec: when TransitGateway.ID is set, its expected that there exist a TransitGateway with ID or else system will give error. when TransitGateway.Name is set, system will first check for TransitGateway with Name, if not exist system will create new TransitGateway. properties: + globalRouting: + description: |- + globalRouting indicates whether to set global routing true or not while creating the transit gateway. + set this field to true only when PowerVS and VPC are from different regions, if they are same it's suggested to use local routing by setting the field to false. + when the field is omitted, based on PowerVS region (region associated with IBMPowerVSCluster.Spec.Zone) and VPC region(IBMPowerVSCluster.Spec.VPC.Region) system will decide whether to enable globalRouting or not. + type: boolean id: description: id of resource. type: string diff --git a/util/util.go b/util/util.go index deb85d576..450b3ce1d 100644 --- a/util/util.go +++ b/util/util.go @@ -197,3 +197,11 @@ func VPCZonesForPowerVSRegion(region string) ([]string, error) { } return nil, fmt.Errorf("VPC zones corresponding to a PowerVS region %s not found ", region) } + +// IsGlobalRoutingRequiredForTG returns true when powervs and vpc regions are different. +func IsGlobalRoutingRequiredForTG(powerVSRegion string, vpcRegion string) bool { + if r, ok := Regions[powerVSRegion]; ok && r.VPCRegion == vpcRegion { + return false + } + return true +}