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

Refactor PowerVSClusterscope function to faciliate UT integration #1827

Merged
merged 1 commit into from
Jul 2, 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
213 changes: 128 additions & 85 deletions cloud/scope/powervs_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,26 @@ type PowerVSClusterScopeParams struct {
Cluster *capiv1beta1.Cluster
IBMPowerVSCluster *infrav1beta2.IBMPowerVSCluster
ServiceEndpoint []endpoints.ServiceEndpoint

// ClientFactory contains collection of functions to override actual client, which helps in testing.
ClientFactory
}

// ClientFactory is collection of function used for overriding actual clients to help in testing.
type ClientFactory struct {
AuthenticatorFactory func() (core.Authenticator, error)
PowerVSClientFactory func() (powervs.PowerVS, error)
VPCClientFactory func() (vpc.Vpc, error)
TransitGatewayFactory func() (transitgateway.TransitGateway, error)
ResourceControllerFactory func() (resourcecontroller.ResourceController, error)
ResourceManagerFactory func() (resourcemanager.ResourceManager, error)
}

// PowerVSClusterScope defines a scope defined around a Power VS Cluster.
type PowerVSClusterScope struct {
logr.Logger
Client client.Client
patchHelper *patch.Helper
session *ibmpisession.IBMPISession

IBMPowerVSClient powervs.PowerVS
IBMVPCClient vpc.Vpc
Expand All @@ -105,7 +117,7 @@ type PowerVSClusterScope struct {
}

// NewPowerVSClusterScope creates a new PowerVSClusterScope from the supplied parameters.
func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterScope, error) { //nolint:gocyclo
func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterScope, error) {
if params.Client == nil {
err := errors.New("failed to generate new scope as client is nil")
return nil, err
Expand All @@ -128,7 +140,20 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
return nil, err
}

options := powervs.ServiceOptions{
// if powervs.cluster.x-k8s.io/create-infra=true annotation is not set, create only powerVSClient.
if !CheckCreateInfraAnnotation(*params.IBMPowerVSCluster) {
return &PowerVSClusterScope{
Logger: params.Logger,
Client: params.Client,
patchHelper: helper,
Cluster: params.Cluster,
IBMPowerVSCluster: params.IBMPowerVSCluster,
ServiceEndpoint: params.ServiceEndpoint,
}, nil
}

// if powervs.cluster.x-k8s.io/create-infra=true annotation is set, create necessary clients.
piOptions := powervs.ServiceOptions{
IBMPIOptions: &ibmpisession.IBMPIOptions{
Debug: params.Logger.V(DEBUGLEVEL).Enabled(),
},
Expand Down Expand Up @@ -164,76 +189,27 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
if err != nil {
return nil, fmt.Errorf("failed to get resource instance: %w", err)
}
options.Zone = *res.RegionID
options.CloudInstanceID = params.IBMPowerVSCluster.Spec.ServiceInstanceID
piOptions.Zone = *res.RegionID
piOptions.CloudInstanceID = params.IBMPowerVSCluster.Spec.ServiceInstanceID
} else {
options.Zone = *params.IBMPowerVSCluster.Spec.Zone
piOptions.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 {
return nil, fmt.Errorf("failed to create PowerVS client %w", err)
}

auth, err := authenticator.GetAuthenticator()
// Get the authenticator.
auth, err := params.getAuthenticator()
if err != nil {
return nil, fmt.Errorf("failed to create authenticator %w", err)
}
account, err := utils.GetAccount(auth)
if err != nil {
return nil, fmt.Errorf("failed to get account details %w", err)
}
piOptions.Authenticator = auth

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)
// Create PowerVS client.
powerVSClient, err := params.getPowerVSClient(piOptions)
if err != nil {
return nil, fmt.Errorf("failed to get PowerVS session %w", err)
}

// if powervs.cluster.x-k8s.io/create-infra=true annotation is not set, create only powerVSClient.
if !CheckCreateInfraAnnotation(*params.IBMPowerVSCluster) {
return &PowerVSClusterScope{
session: session,
Logger: params.Logger,
Client: params.Client,
patchHelper: helper,
Cluster: params.Cluster,
IBMPowerVSCluster: params.IBMPowerVSCluster,
ServiceEndpoint: params.ServiceEndpoint,
IBMPowerVSClient: powerVSClient,
}, nil
}

// if powervs.cluster.x-k8s.io/create-infra=true annotation is set, create necessary clients.
if params.IBMPowerVSCluster.Spec.VPC == nil || params.IBMPowerVSCluster.Spec.VPC.Region == nil {
return nil, fmt.Errorf("failed to create VPC client as VPC info is nil")
}

if params.Logger.V(DEBUGLEVEL).Enabled() {
core.SetLoggingLevel(core.LevelDebug)
return nil, fmt.Errorf("failed to create PowerVS client %w", err)
}

// Fetch the VPC service endpoint.
svcEndpoint := endpoints.FetchVPCEndpoint(*params.IBMPowerVSCluster.Spec.VPC.Region, params.ServiceEndpoint)

// Create VPC client.
vpcClient, err := vpc.NewService(svcEndpoint)
vpcClient, err := params.getVPCClient()
if err != nil {
return nil, fmt.Errorf("failed to create VPC client: %w", err)
}
Expand All @@ -242,14 +218,8 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
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)
tgClient, err := params.getTransitGatewayClient(tgOptions)
if err != nil {
return nil, fmt.Errorf("failed to create tranist gateway client: %w", err)
}
Expand All @@ -260,13 +230,8 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
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)

resourceClient, err := params.getResourceControllerClient(serviceOption)
if err != nil {
return nil, fmt.Errorf("failed to create resource controller client: %w", err)
}
Expand All @@ -276,19 +241,12 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
Authenticator: auth,
}

rmEndpoint := endpoints.FetchEndpoints(string(endpoints.RM), params.ServiceEndpoint)
if rmEndpoint != "" {
rcManagerOptions.URL = rmEndpoint
params.Logger.V(3).Info("Overriding the default resource manager endpoint", "ResourceManagerEndpoint", rmEndpoint)
}

rmClient, err := resourcemanager.NewService(rcManagerOptions)
rmClient, err := params.getResourceManagerClient(rcManagerOptions)
if err != nil {
return nil, fmt.Errorf("failed to create resource manager client: %w", err)
}

clusterScope := &PowerVSClusterScope{
session: session,
Logger: params.Logger,
Client: params.Client,
patchHelper: helper,
Expand All @@ -304,6 +262,81 @@ func NewPowerVSClusterScope(params PowerVSClusterScopeParams) (*PowerVSClusterSc
return clusterScope, nil
}

func (params PowerVSClusterScopeParams) getAuthenticator() (core.Authenticator, error) {
if params.AuthenticatorFactory != nil {
return params.AuthenticatorFactory()
}
return authenticator.GetAuthenticator()
}

func (params PowerVSClusterScopeParams) getPowerVSClient(options powervs.ServiceOptions) (powervs.PowerVS, error) {
if params.PowerVSClientFactory != nil {
return params.PowerVSClientFactory()
}

// 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.URL = powerVSServiceEndpoint
}
return powervs.NewService(options)
}

func (params PowerVSClusterScopeParams) getVPCClient() (vpc.Vpc, error) {
if params.Logger.V(DEBUGLEVEL).Enabled() {
core.SetLoggingLevel(core.LevelDebug)
}
if params.VPCClientFactory != nil {
return params.VPCClientFactory()
}
if params.IBMPowerVSCluster.Spec.VPC == nil || params.IBMPowerVSCluster.Spec.VPC.Region == nil {
return nil, fmt.Errorf("failed to create VPC client as VPC info is nil")
}
// Fetch the VPC service endpoint.
svcEndpoint := endpoints.FetchVPCEndpoint(*params.IBMPowerVSCluster.Spec.VPC.Region, params.ServiceEndpoint)
return vpc.NewService(svcEndpoint)
}

func (params PowerVSClusterScopeParams) getTransitGatewayClient(options *tgapiv1.TransitGatewayApisV1Options) (transitgateway.TransitGateway, error) {
if params.TransitGatewayFactory != nil {
return params.TransitGatewayFactory()
}
// 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)
options.URL = tgServiceEndpoint
}
return transitgateway.NewService(options)
}

func (params PowerVSClusterScopeParams) getResourceControllerClient(options resourcecontroller.ServiceOptions) (resourcecontroller.ResourceController, error) {
if params.ResourceControllerFactory != nil {
return params.ResourceControllerFactory()
}
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
options.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}
return resourcecontroller.NewService(options)
}

func (params PowerVSClusterScopeParams) getResourceManagerClient(options *resourcemanagerv2.ResourceManagerV2Options) (resourcemanager.ResourceManager, error) {
if params.ResourceManagerFactory != nil {
return params.ResourceManagerFactory()
}
// Fetch the resource manager endpoint.
rmEndpoint := endpoints.FetchEndpoints(string(endpoints.RM), params.ServiceEndpoint)
if rmEndpoint != "" {
options.URL = rmEndpoint
params.Logger.V(3).Info("Overriding the default resource manager endpoint", "ResourceManagerEndpoint", rmEndpoint)
}
return resourcemanager.NewService(options)
}

// PatchObject persists the cluster configuration and status.
func (s *PowerVSClusterScope) PatchObject() error {
return s.patchHelper.Patch(context.TODO(), s.IBMPowerVSCluster)
Expand Down Expand Up @@ -2183,8 +2216,18 @@ func (s *PowerVSClusterScope) fetchResourceGroupID() (string, error) {
return "", fmt.Errorf("resource group name is not set")
}

auth, err := authenticator.GetAuthenticator()
if err != nil {
return "", err
}

account, err := utils.GetAccount(auth)
if err != nil {
return "", err
}

resourceGroup := s.ResourceGroup().Name
rmv2ListResourceGroupOpt := resourcemanagerv2.ListResourceGroupsOptions{Name: resourceGroup, AccountID: &s.session.Options.UserAccount}
rmv2ListResourceGroupOpt := resourcemanagerv2.ListResourceGroupsOptions{Name: resourceGroup, AccountID: &account}
resourceGroupListResult, _, err := s.ResourceManagerClient.ListResourceGroups(&rmv2ListResourceGroupOpt)
if err != nil {
return "", err
Expand Down
Loading