diff --git a/pkg/cmd/kafka/create/create.go b/pkg/cmd/kafka/create/create.go index 6dc97d627..ff8fb2e06 100644 --- a/pkg/cmd/kafka/create/create.go +++ b/pkg/cmd/kafka/create/create.go @@ -75,7 +75,9 @@ type options struct { kfmClusterList *kafkamgmtclient.EnterpriseClusterList selectedCluster *kafkamgmtclient.EnterpriseCluster clusterMap *map[string]v1.Cluster - useEnterpriseCluster bool + useEnterpriseFlow bool + hasLegacyQuota bool + useLegacyFlow bool clusterManagementApiUrl string accessToken string @@ -501,58 +503,88 @@ func selectEnterpriseOrRHInfraPrompt(opts *options) error { if err != nil { return err } - opts.useEnterpriseCluster = idx != 0 + opts.useEnterpriseFlow = idx != 0 + opts.useLegacyFlow = idx == 0 return nil } +func checkForLegacyQuota(opts *options, orgQuotas *accountmgmtutil.OrgQuotas) { + // Check if the user has enterprise quota + for _, quota := range orgQuotas.EnterpriseQuotas { + if quota.Quota > 0 { + opts.useEnterpriseFlow = true + } + } + // to-do may have to deal with trial (developer instances) quota here + + // Check if the user has a legacy quota + for _, quota := range orgQuotas.StandardQuotas { + if quota.Quota > 0 { + opts.hasLegacyQuota = true + return + } + } + for _, quota := range orgQuotas.MarketplaceQuotas { + if quota.Quota > 0 { + opts.hasLegacyQuota = true + return + } + } + for _, quota := range orgQuotas.EvalQuotas { + if quota.Quota > 0 { + opts.hasLegacyQuota = true + return + } + } +} + // Show a prompt to allow the user to interactively insert the data for their Kafka // nolint:funlen func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants) (*kafkamgmtclient.KafkaRequestPayload, error) { f := opts.f - validator := &kafkacmdutil.Validator{ - Localizer: f.Localizer, - Connection: f.Connection, + // getting org quotas + orgQuota, err := accountmgmtutil.GetOrgQuotas(f, &constants.Kafka.Ams) + if err != nil { + return nil, err } - promptName := &survey.Input{ - Message: f.Localizer.MustLocalize("kafka.create.input.name.message"), - Help: f.Localizer.MustLocalize("kafka.create.input.name.help"), - } + // check if org has legacy (non-hybrid) quota + checkForLegacyQuota(opts, orgQuota) + + var enterpriseQuota accountmgmtutil.QuotaSpec answers := &promptAnswers{} - err := survey.AskOne(promptName, &answers.Name, survey.WithValidator(validator.ValidateName), survey.WithValidator(validator.ValidateNameIsAvailable)) + // Message the user with a link to get enterprise quota if they don't have any + if !opts.useEnterpriseFlow { + f.Logger.Info(opts.f.Localizer.MustLocalize("kafka.create.info.enterpriseQuota")) + } + + answers, err = promptForKafkaName(f, answers) if err != nil { return nil, err } - // Get the list of enterprise clusters in the users organization if there are any, creates a map of cluster ids to names to include names in the prompt + // Get the list of enterprise clusters in the users organization if there are any, creates a map of cluster ids + // to names to include names in the prompt kfmClusterList, clusterMap, err := setEnterpriseClusterList(opts) if err != nil { return nil, err } - opts.kfmClusterList = kfmClusterList opts.clusterMap = clusterMap - // If there are enterprise clusters in the user's organization, prompt them to select one using the interactive prompt for enterprise flow - if len(opts.kfmClusterList.Items) > 0 { - err = selectEnterpriseOrRHInfraPrompt(opts) - if err != nil { - return nil, err - } - } - - // getting org quotas - orgQuota, err := accountmgmtutil.GetOrgQuotas(f, &constants.Kafka.Ams) + // If there are enterprise clusters in the user's organization, prompt them to select a flow (enterprise or legacy) + // using the interactive prompt. If there are no enterprise clusters, the user must use the legacy flow. + // Default to enterprise flow + err = determineFlowFromQuota(opts) if err != nil { return nil, err } - var enterpriseQuota accountmgmtutil.QuotaSpec - if opts.useEnterpriseCluster { + if opts.useEnterpriseFlow { if len(orgQuota.EnterpriseQuotas) < 1 { return nil, opts.f.Localizer.MustLocalizeError("kafka.create.error.noEnterpriseQuota") } @@ -582,33 +614,17 @@ func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants } // If the user is not using an enterprise cluster, prompt them to select a cloud provider - if !opts.useEnterpriseCluster { + if opts.useLegacyFlow { answers, err = cloudProviderPrompt(f, answers) if err != nil { return nil, err } } - availableBillingModels := FetchSupportedBillingModels(orgQuota, answers.CloudProvider) - - if len(availableBillingModels) == 0 && len(orgQuota.MarketplaceQuotas) > 0 { - return nil, opts.f.Localizer.MustLocalizeError("kafka.create.provider.error.noStandardInstancesAvailable") - } - - // prompting for billing model if there are more than one available, otherwise using the only one available - if len(availableBillingModels) > 0 { - if len(availableBillingModels) == 1 { - answers.BillingModel = availableBillingModels[0] - } else { - billingModelPrompt := &survey.Select{ - Message: f.Localizer.MustLocalize("kafka.create.input.billingModel.message"), - Options: availableBillingModels, - } - err = survey.AskOne(billingModelPrompt, &answers.BillingModel) - if err != nil { - return nil, err - } - } + // gets the billing model for the kafka, if the user has more than one billing model, a prompt is shown to select one + answers, err = getBillingModel(opts, orgQuota, answers) + if err != nil { + return nil, err } // if billing model is marketplace, prompt for marketplace provider and account id @@ -623,7 +639,7 @@ func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants // nolint:staticcheck payload := &kafkamgmtclient.KafkaRequestPayload{} - if opts.useEnterpriseCluster { + if opts.useEnterpriseFlow { /* if using dedicated cluster option then get the supported sizes for this cluster based on the sizes it supports the user to select the one they want to use @@ -757,6 +773,67 @@ func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants return payload, nil } +func getBillingModel(opts *options, orgQuota *accountmgmtutil.OrgQuotas, answers *promptAnswers) (*promptAnswers, error) { + availableBillingModels := FetchSupportedBillingModels(orgQuota, answers.CloudProvider) + + if len(availableBillingModels) == 0 && len(orgQuota.MarketplaceQuotas) > 0 { + return nil, opts.f.Localizer.MustLocalizeError("kafka.create.provider.error.noStandardInstancesAvailable") + } + + // prompting for billing model if there are more than one available, otherwise using the only one available + if len(availableBillingModels) > 0 { + if len(availableBillingModels) == 1 { + answers.BillingModel = availableBillingModels[0] + } else { + billingModelPrompt := &survey.Select{ + Message: opts.f.Localizer.MustLocalize("kafka.create.input.billingModel.message"), + Options: availableBillingModels, + } + err := survey.AskOne(billingModelPrompt, &answers.BillingModel) + if err != nil { + return nil, err + } + } + } + return answers, nil +} + +func determineFlowFromQuota(opts *options) error { + switch { + case len(opts.kfmClusterList.Items) > 0 && opts.hasLegacyQuota: + err := selectEnterpriseOrRHInfraPrompt(opts) + if err != nil { + return err + } + return nil + case opts.hasLegacyQuota: + opts.useLegacyFlow = true + return nil + default: + opts.useEnterpriseFlow = true + return nil + } +} + +func promptForKafkaName(f *factory.Factory, answers *promptAnswers) (*promptAnswers, error) { + validator := &kafkacmdutil.Validator{ + Localizer: f.Localizer, + Connection: f.Connection, + } + + // prompt for kafka name + promptName := &survey.Input{ + Message: f.Localizer.MustLocalize("kafka.create.input.name.message"), + Help: f.Localizer.MustLocalize("kafka.create.input.name.help"), + } + + err := survey.AskOne(promptName, &answers.Name, survey.WithValidator(validator.ValidateName), survey.WithValidator(validator.ValidateNameIsAvailable)) + if err != nil { + return nil, err + } + return answers, nil +} + func marketplaceQuotaPrompt(orgQuota *accountmgmtutil.OrgQuotas, answers *promptAnswers, f *factory.Factory) (*promptAnswers, error) { validMarketPlaces := FetchValidMarketplaces(orgQuota.MarketplaceQuotas, answers.CloudProvider) if len(validMarketPlaces) == 1 { diff --git a/pkg/core/localize/locales/en/cmd/dedicated.en.toml b/pkg/core/localize/locales/en/cmd/dedicated.en.toml index d33828601..e8f9b57c4 100644 --- a/pkg/core/localize/locales/en/cmd/dedicated.en.toml +++ b/pkg/core/localize/locales/en/cmd/dedicated.en.toml @@ -167,3 +167,4 @@ You can check for when your cluster status is "ready" by running the following c rhoas dedicated list ''' + diff --git a/pkg/core/localize/locales/en/cmd/kafka.en.toml b/pkg/core/localize/locales/en/cmd/kafka.en.toml index 14cc07b9f..dcd6e8368 100644 --- a/pkg/core/localize/locales/en/cmd/kafka.en.toml +++ b/pkg/core/localize/locales/en/cmd/kafka.en.toml @@ -1213,3 +1213,10 @@ one = 'Red Hat Managed OpenShift Cluster for your Kafka Instances' [kafka.create.input.cluster.help] one = 'Select the cluster to provision your Kafka instance on.' + +[kafka.create.info.enterpriseQuota] +one = ''' +You do not have enough quota to create a Kafka instance on your own OpenShift Cluster. + +Please visit https://console.redhat.com/application-services/streams/overview to request more quota. +''' \ No newline at end of file