Skip to content

Commit

Permalink
Add support to override service endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Karthik-K-N committed Mar 12, 2024
1 parent 21b92d6 commit 9f2e34b
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 58 deletions.
4 changes: 4 additions & 0 deletions api/v1beta2/ibmpowervscluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ func (r *IBMPowerVSCluster) validateIBMPowerVSClusterCreateInfraPrereq() *field.
return field.Invalid(field.NewPath("spec.zone"), r.Spec.Zone, "value of zone is empty")
}

if r.Spec.VPC == nil {
return field.Invalid(field.NewPath("spec.vpc"), r.Spec.VPC, "value of VPC is empty")
}

if r.Spec.VPC.Region == nil {
return field.Invalid(field.NewPath("spec.vpc.region"), r.Spec.VPC.Region, "value of VPC region is empty")
}
Expand Down
84 changes: 77 additions & 7 deletions cloud/scope/powervs_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import (
"github.com/IBM-Cloud/power-go-client/power/client/datacenters"
"github.com/IBM-Cloud/power-go-client/power/models"
"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/ibm-cos-sdk-go/aws"
"github.com/IBM/ibm-cos-sdk-go/aws/awserr"
cosSession "github.com/IBM/ibm-cos-sdk-go/aws/session"
"github.com/IBM/ibm-cos-sdk-go/service/s3"
tgapiv1 "github.com/IBM/networking-go-sdk/transitgatewayapisv1"
"github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"
Expand Down Expand Up @@ -130,14 +132,23 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc

// if Spec.ServiceInstanceID is set fetch zone associated with it or else use Spec.Zone.
if params.IBMPowerVSCluster.Spec.ServiceInstanceID != "" {
rc, err := resourcecontroller.NewService(resourcecontroller.ServiceOptions{})
// Create Resource Controller client.
var serviceOption resourcecontroller.ServiceOptions
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
serviceOption.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}
rc, err := resourcecontroller.NewService(serviceOption)
if err != nil {
return nil, err
}

// Fetch the resource controller endpoint.
if rcEndpoint := endpoints.FetchRCEndpoint(params.ServiceEndpoint); rcEndpoint != "" {
if err := rc.SetServiceURL(rcEndpoint); err != nil {
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
return nil, fmt.Errorf("failed to set resource controller endpoint: %w", err)
}
}
Expand All @@ -156,6 +167,13 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
options.Zone = *params.IBMPowerVSCluster.Spec.Zone
}

// Fetch the PowerVS service endpoint.
powerVSServiceEndpoint := endpoints.FetchEndpoints(string(endpoints.PowerVS), params.ServiceEndpoint)
if powerVSServiceEndpoint != "" {
params.Logger.V(3).Info("Overriding the default PowerVS endpoint", "powerVSEndpoint", powerVSServiceEndpoint)
options.IBMPIOptions.URL = powerVSServiceEndpoint
}

// TODO(karhtik-k-n): may be optimize NewService to use the session created here
powerVSClient, err := powervs.NewService(options)
if err != nil {
Expand All @@ -170,11 +188,15 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
if err != nil {
return nil, fmt.Errorf("error failed to get account details %w", err)
}
// TODO(Karthik-k-n): Handle dubug and URL options.

sessionOptions := &ibmpisession.IBMPIOptions{
Authenticator: auth,
UserAccount: account,
Zone: options.Zone,
Debug: params.Logger.V(DEBUGLEVEL).Enabled(),
}
if powerVSServiceEndpoint != "" {
sessionOptions.URL = powerVSServiceEndpoint
}
session, err := ibmpisession.NewIBMPISession(sessionOptions)
if err != nil {
Expand Down Expand Up @@ -210,13 +232,35 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
return nil, fmt.Errorf("error failed to create IBM VPC client: %w", err)
}

tgClient, err := transitgateway.NewService()
// Create TransitGateway client
tgOptions := &tgapiv1.TransitGatewayApisV1Options{
Authenticator: auth,
}
// Fetch the TransitGateway service endpoint.
tgServiceEndpoint := endpoints.FetchEndpoints(string(endpoints.TransitGateway), params.ServiceEndpoint)
if tgServiceEndpoint != "" {
params.Logger.V(3).Info("Overriding the default TransitGateway endpoint", "transitGatewayEndpoint", tgServiceEndpoint)
tgOptions.URL = tgServiceEndpoint
}

tgClient, err := transitgateway.NewService(tgOptions)
if err != nil {
return nil, fmt.Errorf("error failed to create tranist gateway client: %w", err)
}

// TODO(karthik-k-n): consider passing auth in options to resource controller
resourceClient, err := resourcecontroller.NewService(resourcecontroller.ServiceOptions{})
// Create Resource Controller client.
serviceOption := resourcecontroller.ServiceOptions{
ResourceControllerV2Options: &resourcecontrollerv2.ResourceControllerV2Options{
Authenticator: auth,
},
}
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
serviceOption.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}
resourceClient, err := resourcecontroller.NewService(serviceOption)
if err != nil {
return nil, fmt.Errorf("error failed to create resource client: %w", err)
}
Expand Down Expand Up @@ -298,6 +342,7 @@ func (s *PowerVSClusterScope) GetServiceInstanceID() string {

// SetStatus set the IBMPowerVSCluster status for provided ResourceType.
func (s *PowerVSClusterScope) SetStatus(resourceType infrav1beta2.ResourceType, resource infrav1beta2.ResourceReference) {
s.V(3).Info("Setting status", "resourceType", resourceType, "resource", resource)
switch resourceType {
case infrav1beta2.ResourceTypeServiceInstance:
if s.IBMPowerVSCluster.Status.ServiceInstance == nil {
Expand Down Expand Up @@ -1404,9 +1449,34 @@ func (s *PowerVSClusterScope) ReconcileCOSInstance() error {
if !ok {
return fmt.Errorf("ibmcloud api key is not provided, set %s environmental variable", "IBMCLOUD_API_KEY")
}
region := s.IBMPowerVSCluster.Spec.CosInstance.BucketRegion
// if the bucket region is not set, use vpc region
if region == "" {
vpcDetails := s.VPC()
if vpcDetails == nil || vpcDetails.Region == nil {
return fmt.Errorf("failed to determine cos bucket region, both buckeet region and vpc region not set")
}
region = *vpcDetails.Region
}

serviceEndpoint := fmt.Sprintf("s3.%s.%s", region, cosURLDomain)
// Fetch the COS service endpoint.
cosSvcEndpoint := endpoints.FetchEndpoints(string(endpoints.COS), s.ServiceEndpoint)
if cosSvcEndpoint != "" {
s.Logger.V(3).Info("Overriding the default COS endpoint", "cosEndpoint", cosSvcEndpoint)
serviceEndpoint = cosSvcEndpoint
}

cosOptions := cos.ServiceOptions{
Options: &cosSession.Options{
Config: aws.Config{
Endpoint: &serviceEndpoint,
Region: &region,
},
},
}

// TODO: if bucket region is not set, fetch associated vpc region
cosClient, err := cos.NewService(cos.ServiceOptions{}, s.IBMPowerVSCluster.Spec.CosInstance.BucketRegion, apiKey, *cosServiceInstanceStatus.GUID)
cosClient, err := cos.NewService(cosOptions, apiKey, *cosServiceInstanceStatus.GUID)
if err != nil {
s.Error(err, "error creating cosClient")
return fmt.Errorf("failed to create cos client: %w", err)
Expand Down
19 changes: 10 additions & 9 deletions cloud/scope/powervs_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,18 @@ func NewPowerVSImageScope(params PowerVSImageScopeParams) (scope *PowerVSImageSc
}
scope.patchHelper = helper

rc, err := resourcecontroller.NewService(resourcecontroller.ServiceOptions{})
if err != nil {
return nil, err
// Create Resource Controller client.
var serviceOption resourcecontroller.ServiceOptions
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
serviceOption.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}

// Fetch the resource controller endpoint.
if rcEndpoint := endpoints.FetchRCEndpoint(params.ServiceEndpoint); rcEndpoint != "" {
if err := rc.SetServiceURL(rcEndpoint); err != nil {
return nil, fmt.Errorf("failed to set resource controller endpoint: %w", err)
}
scope.Logger.V(3).Info("Overriding the default resource controller endpoint")
rc, err := resourcecontroller.NewService(serviceOption)
if err != nil {
return nil, err
}

var serviceInstanceID string
Expand Down
42 changes: 39 additions & 3 deletions cloud/scope/powervs_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/IBM-Cloud/power-go-client/power/models"
"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/ibm-cos-sdk-go/aws"
cosSession "github.com/IBM/ibm-cos-sdk-go/aws/session"
"github.com/IBM/ibm-cos-sdk-go/service/s3"
"github.com/IBM/vpc-go-sdk/vpcv1"

Expand Down Expand Up @@ -146,7 +147,16 @@ func NewPowerVSMachineScope(params PowerVSMachineScopeParams) (scope *PowerVSMac
}
scope.patchHelper = helper

rc, err := resourcecontroller.NewService(resourcecontroller.ServiceOptions{})
// Create Resource Controller client.
var serviceOption resourcecontroller.ServiceOptions
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
serviceOption.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}

rc, err := resourcecontroller.NewService(serviceOption)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -577,12 +587,38 @@ func (m *PowerVSMachineScope) createCOSClient() (*cos.Service, error) {
fmt.Printf("ibmcloud api key is not provided, set %s environmental variable", "IBMCLOUD_API_KEY")
}

cosClient, err := cos.NewService(cos.ServiceOptions{}, m.IBMPowerVSCluster.Spec.CosInstance.BucketRegion, apiKey, *serviceInstance.GUID)
region := m.IBMPowerVSCluster.Spec.CosInstance.BucketRegion
// if the bucket region is not set, use vpc region
if region == "" {
vpcDetails := m.IBMPowerVSCluster.Spec.VPC
if vpcDetails == nil || vpcDetails.Region == nil {
return nil, fmt.Errorf("failed to determine cos bucket region, both buckeet region and vpc region not set")
}
region = *vpcDetails.Region
}

serviceEndpoint := fmt.Sprintf("s3.%s.%s", region, cosURLDomain)
// Fetch the COS service endpoint.
cosServiceEndpoint := endpoints.FetchEndpoints(string(endpoints.COS), m.ServiceEndpoint)
if cosServiceEndpoint != "" {
m.Logger.V(3).Info("Overriding the default COS endpoint", "cosEndpoint", cosServiceEndpoint)
serviceEndpoint = cosServiceEndpoint
}

cosOptions := cos.ServiceOptions{
Options: &cosSession.Options{
Config: aws.Config{
Endpoint: &serviceEndpoint,
Region: &region,
},
},
}

cosClient, err := cos.NewService(cosOptions, apiKey, *serviceInstance.GUID)
if err != nil {
m.Error(err, "failed to create cos client")
return nil, fmt.Errorf("failed to create cos client: %w", err)
}

return cosClient, nil
}

Expand Down
2 changes: 1 addition & 1 deletion docs/book/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ it into a management cluster using `clusterctl`.
> `${ServiceRegion1}:${ServiceID1}=${URL1},${ServiceID2}=${URL2};${ServiceRegion2}:${ServiceID1}=${URL1...}`.

Supported ServiceIDs include - `vpc, powervs, rc`
Supported ServiceIDs include - `vpc, powervs, rc, cos, transitgateway`
```console
export SERVICE_ENDPOINT=us-south:vpc=https://us-south-stage01.iaasdev.cloud.ibm.com,powervs=https://dal.power-iaas.test.cloud.ibm.com,rc=https://resource-controller.test.cloud.ibm.com
```
Expand Down
41 changes: 16 additions & 25 deletions pkg/cloud/services/cos/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package cos

import (
"fmt"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -92,36 +91,28 @@ func (s *Service) PutPublicAccessBlock(input *s3.PutPublicAccessBlockInput) (*s3
}

// NewService returns a new service for the IBM Cloud Resource Controller api client.
// TODO(karthik-k-n): pass location as a part of options.
func NewService(options ServiceOptions, location, apikey, serviceInstance string) (*Service, error) {
func NewService(options ServiceOptions, apikey, serviceInstance string) (*Service, error) {
if options.Options == nil {
options.Options = &cosSession.Options{}
}
serviceEndpoint := fmt.Sprintf("s3.%s.%s", location, cosURLDomain)
// TODO(karthik-k-n): handle URL
options.Config = aws.Config{
Endpoint: &serviceEndpoint,
Region: &location,
HTTPClient: &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return httpproxy.FromEnvironment().ProxyFunc()(req.URL)
},
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
options.Config.S3ForcePathStyle = aws.Bool(true)
options.Config.HTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return httpproxy.FromEnvironment().ProxyFunc()(req.URL)
},
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
S3ForcePathStyle: aws.Bool(true),
}

options.Config.Credentials = ibmiam.NewStaticCredentials(aws.NewConfig(), iamEndpoint, apikey, serviceInstance)

sess, err := cosSession.NewSessionWithOptions(*options.Options)
Expand Down
10 changes: 6 additions & 4 deletions pkg/cloud/services/resourcecontroller/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ func NewService(options ServiceOptions) (*Service, error) {
if options.ResourceControllerV2Options == nil {
options.ResourceControllerV2Options = &resourcecontrollerv2.ResourceControllerV2Options{}
}
auth, err := authenticator.GetAuthenticator()
if err != nil {
return nil, err
if options.Authenticator == nil {
auth, err := authenticator.GetAuthenticator()
if err != nil {
return nil, err
}
options.Authenticator = auth
}
options.Authenticator = auth
service, err := resourcecontrollerv2.NewResourceControllerV2(options.ResourceControllerV2Options)
if err != nil {
return nil, err
Expand Down
20 changes: 12 additions & 8 deletions pkg/cloud/services/transitgateway/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ type Service struct {
}

// NewService returns a new service for the IBM Cloud Transit Gateway api client.
func NewService() (TransitGateway, error) {
auth, err := authenticator.GetAuthenticator()
if err != nil {
return nil, err
func NewService(options *tgapiv1.TransitGatewayApisV1Options) (TransitGateway, error) {
if options == nil {
options = &tgapiv1.TransitGatewayApisV1Options{}
}
if options.Authenticator == nil {
auth, err := authenticator.GetAuthenticator()
if err != nil {
return nil, err
}
options.Authenticator = auth
}
tgClient, err := tgapiv1.NewTransitGatewayApisV1(&tgapiv1.TransitGatewayApisV1Options{
Authenticator: auth,
Version: pointer.String(currentDate),
})
options.Version = pointer.String(currentDate)
tgClient, err := tgapiv1.NewTransitGatewayApisV1(options)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 9f2e34b

Please sign in to comment.