Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to override service endpoints #1648

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
cosServiceEndpoint := endpoints.FetchEndpoints(string(endpoints.COS), s.ServiceEndpoint)
if cosServiceEndpoint != "" {
s.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,
},
},
}

// 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