feat(kafka create): add billing model logic#1636
feat(kafka create): add billing model logic#1636rkpattnaik780 merged 13 commits intoredhat-developer:mainfrom
Conversation
|
|
||
| if opts.bypassChecks && (opts.marketplace != "" || opts.marketplaceAcctId != "") { | ||
| if opts.bypassChecks && (opts.marketplace != "" || opts.marketplaceAcctId != "" || opts.billingModel != "") { | ||
| return f.Localizer.MustLocalizeError("kafka.create.error.bypassChecks.marketplace") |
There was a problem hiding this comment.
Description needs billing model flag
pkg/cmd/kafka/create/create.go
Outdated
| return f.Localizer.MustLocalizeError("kafka.create.error.bypassChecks.marketplace") | ||
| } | ||
|
|
||
| if opts.billingModel == "standard" && (opts.marketplaceAcctId != "" || opts.marketplace != "") { |
There was a problem hiding this comment.
I would suggest to not list any billing model in create.go. Also not hardcoding it's value.
| return GetCloudProviderRegionCompletionValues(f, opts.provider) | ||
| }) | ||
|
|
||
| _ = cmd.RegisterFlagCompletionFunc(FlagSize, func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { |
pkg/cmd/kafka/create/create.go
Outdated
| } | ||
|
|
||
| userInstanceType, err = accountmgmtutil.GetUserSupportedInstanceType(f.Context, &constants.Kafka.Ams, conn) | ||
| marketplaceInfo := accountmgmtutil.MarketplaceInfo{ |
There was a problem hiding this comment.
Can be transformed as inline structure passed to method.
pkg/cmd/kafka/create/create.go
Outdated
| userInstanceType, err = accountmgmtutil.GetUserSupportedInstanceType(f, &constants.Kafka.Ams, marketplaceInfo) | ||
| if err != nil || userInstanceType == nil { | ||
| return f.Localizer.MustLocalizeError("kafka.create.error.userInstanceType.notFound") | ||
| return err // || f.Localizer.MustLocalizeError("kafka.create.error.userInstanceType.notFound") |
There was a problem hiding this comment.
userInstanceType == nil will print Error: nil to user
pkg/cmd/kafka/create/create.go
Outdated
|
|
||
| } | ||
|
|
||
| if userInstanceType.BillingModel == "standard" || userInstanceType.BillingModel == "marketplace" { |
There was a problem hiding this comment.
There are no other billing models and if they would be in future we should still pass them. I think this is redundant.
| } | ||
| } | ||
|
|
||
| marketplaces, err := accountmgmtutil.GetValidMarketplaces(f.Context, f.Connection) |
There was a problem hiding this comment.
If we want to ask user to pick marketplace details this should happen before size and feed back into size (this is current bug in relased version of the CLI). I do not see how interactive mode would work with marketplace right now. Would we fail/still require users to use flags for non interactive selects?
pkg/shared/accountmgmtutil/ams.go
Outdated
| } else if quotaResource.GetProduct() == spec.InstanceQuotaID { | ||
| remainingQuota := int(quota.GetAllowed() - quota.GetConsumed()) | ||
| quotas = append(quotas, QuotaSpec{QuotaStandardType, remainingQuota, quotaResource.BillingModel}) | ||
| if quotaResource.BillingModel == "standard" { |
There was a problem hiding this comment.
This seems redundant - standard will still have cloudAccounts with nil value.
It is never a bad idea to debug your code for understanding.
| } | ||
|
|
||
| return amsType, nil | ||
| type OrgQuotas struct { |
There was a problem hiding this comment.
While this is good I would myself keep all Quota spec as array and use filter flags (billingModel) to filter them out.
There is big decision that we can take:
- Have trial as quota object (it will be always there) thus if logic is `len(quotas) == 1 { return quotas[0] }
- Ignore trial and do not return quota for it (it will be more accurate from business logic point of view , but it will require rewrite of the create.go logic.
pkg/shared/accountmgmtutil/ams.go
Outdated
|
|
||
| func SelectQuotaForUser(f *factory.Factory, orgQuota *OrgQuotas, marketplaceInfo MarketplaceInfo) (*QuotaSpec, error) { | ||
| if len(orgQuota.StandardQuotas) == 0 && len(orgQuota.MarketplaceQuotas) == 0 { | ||
| if len(orgQuota.TrialQuotas) == 0 { |
There was a problem hiding this comment.
Trial would be always present. Also doesn't need to checked in quota selection.
Decision we need to take here is:
- do we want to fail when user specify rubbish billing model or accoutID that doesn't exist?
- Can we build an decision graph for selection filtering that will be future proof?
I have build diagram to showcase how this would look like for current model
8d44476 to
fa8dc0c
Compare
|
@rkpattnaik780 We are missing verification steps for @jackdelahunt |
| } | ||
|
|
||
| // GetMarketplaceAcctIdCompletionValues returns a list of valid marketplace account IDs for the organization | ||
| func GetMarketplaceAcctIdCompletionValues(f *factory.Factory) (validMarketplaceAcctIDs []string, directive cobra.ShellCompDirective) { |
| validMarketPlaces := FetchValidMarketplaces(orgQuota.MarketplaceQuotas) | ||
| if len(validMarketPlaces) == 1 { | ||
| answers.Marketplace = validMarketPlaces[0] | ||
| } else { |
There was a problem hiding this comment.
How this would work with len(validMarketPlaces) == 0?
There was a problem hiding this comment.
Ignore me. That would not be possible
pkg/shared/accountmgmtutil/ams.go
Outdated
| if marketplace.Provider != "" && marketplace.CloudAccountID != "" { | ||
| if *cloudAccount.CloudProviderId == marketplace.Provider && *cloudAccount.CloudAccountId == marketplace.CloudAccountID { | ||
| matchedQuotas = append(matchedQuotas, quota) | ||
| } | ||
| } else if marketplace.Provider != "" || marketplace.CloudAccountID != "" { |
There was a problem hiding this comment.
Arent those the same if checks?
There was a problem hiding this comment.
This was to handle the case of providing only provider or account ID.
| } | ||
|
|
||
| func GetValidMarketplaces(ctx context.Context, connectionFunc factory.ConnectionFunc) (marketplaces []string, err error) { | ||
| func pickCloudAccount(f *factory.Factory, cloudAccounts *[]amsclient.CloudAccount, market MarketplaceInfo) (*[]amsclient.CloudAccount, error) { |
There was a problem hiding this comment.
Should this method return single object instead of array. It does pick cloud account right?
There was a problem hiding this comment.
Used array to make it easy to use with quotapsec object.
pkg/shared/accountmgmtutil/ams.go
Outdated
| var matchedAccounts []amsclient.CloudAccount | ||
|
|
||
| for _, cloudAccount := range *cloudAccounts { | ||
| if market.Provider != "" || market.CloudAccountID != "" { |
There was a problem hiding this comment.
Those variables are set outside for so we might do them once outside loop?
pkg/shared/accountmgmtutil/ams.go
Outdated
|
|
||
| for _, cloudAccount := range *cloudAccounts { | ||
| if market.Provider != "" || market.CloudAccountID != "" { | ||
| if *cloudAccount.CloudProviderId == market.Provider || *cloudAccount.CloudAccountId == market.CloudAccountID { |
There was a problem hiding this comment.
Question I have:
Do you think we should support people specifying only market.Provider?
Maybe we can just:
| if *cloudAccount.CloudProviderId == market.Provider || *cloudAccount.CloudAccountId == market.CloudAccountID { | |
| if *cloudAccount.CloudProviderId == market.Provider && *cloudAccount.CloudAccountId == market.CloudAccountID { |
To keep this convoluted logic little bit simpler?
There was a problem hiding this comment.
Do you think we should support people specifying only market.Provider?
I will agree not allowing marketplace provider alone can make the logic bit simpler. I will be removing it.
|
@rkpattnaik780 let's do end to end verification for this together. |
|
Ran into an issue. When only trial instances were available setting the billing model (standard or marketplace) did not throw an error as described in the verification steps. |
Hi @jackdelahunt |
Thanks for the catch, PR has been updated. |
|
From what I can do (step 2) LGTM 👍 |
|
I have tried to do "Duncan Test" as start: It has:
Error detail: |
|
@rkpattnaik780 let's do more comprehensive testing with control plane team and mock. Once we have confidence in this we can release. |
| f.Logger.Debug(fmt.Sprintf("Selected quota object: %#v", userQuota)) | ||
| userQuotaJSON, _ := json.MarshalIndent(userQuota, "", " ") | ||
| f.Logger.Debug("Selected Quota object:") | ||
| f.Logger.Debug(string(userQuotaJSON)) |
There was a problem hiding this comment.
Let's create helper for logging that type of stuff. It takes a lot of space.

This PR adds
--billing-modelflag torhoas kafka createcommand.The CLI should be able to create instances with standard, marketplace and trial quotas.
Verification Steps
rhoas kafka create --name test-instanceshould throw error saying multiple quota types are available and user needs to specify billing model.rhoas kafka create --name test-instance --billing-model standardshould create a standard instancerhoas kafka create --name test-instance --billing-model standardshould create a marketplace instancerhoas kafka createshould start the creation in interactive mode and prompt for billing model.User should be able to pick marketplace provider and market place account if multiple options are available, else the only account gets selected by default.
Specifying the billing model should fail with message "only trial instances available".
rhoas kafka create --name test-instanceshould create a trial instance.Interactive mode should not prompt billing model.
Type of change