diff --git a/.github/workflows/gobuild.yml b/.github/workflows/gobuild.yml index 56451d1e3..d3911ce2d 100644 --- a/.github/workflows/gobuild.yml +++ b/.github/workflows/gobuild.yml @@ -21,7 +21,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x - name: Checkout code uses: actions/checkout@v2 - name: golangci-lint diff --git a/.github/workflows/modular-docs-publish.yml b/.github/workflows/modular-docs-publish.yml index ba716a74b..47e3cd544 100644 --- a/.github/workflows/modular-docs-publish.yml +++ b/.github/workflows/modular-docs-publish.yml @@ -3,10 +3,8 @@ name: Downstream docs publish on: - push: - tags: - - 'v*' - #branches: [main] + release: + types: [released] jobs: build: @@ -17,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x - run: make generate-downstream-docs name: Generate generate-downstream-docs - name: Deploy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a2685a2c..b739c40f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x - name: Check tag id: check-tag @@ -74,9 +74,9 @@ jobs: event-type: rhoas-cli-release client-payload: '{"version": steps.set-version.outputs.version }' tools-release: - if: steps.check-tag.outputs.prerelease == 'false' needs: release runs-on: ubuntu-latest + if: needs.release.steps.check-tag.outputs.prerelease == 'false' steps: - uses: actions/checkout@v2 - name: Notify tools repo diff --git a/.vscode/launch.json b/.vscode/launch.json index 01949ad8b..e02817eea 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,6 +27,17 @@ "whoami" ] }, + { + "name": "auth token", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/rhoas", + "env": {}, + "args": [ + "authtoken" + ] + }, { "name": "Logout", "type": "go", diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dd491e6b..fd273bc50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,103 @@ + +## [v0.41.0](https://github.com/redhat-developer/app-services-cli/compare/v0.40.1...v0.41.0) (2022-04-22) + +### Bug Fixes + +* change message for compatibility APIs +* change to info from error +* address review comments +* add remaining commands +* add messages placeholders +* build failing at lint +* expose api config to enable using external clients and APIs ([#1523](https://github.com/redhat-developer/app-services-cli/issues/1523)) +* update client to enable using external clients +* map connector status to row ([#1518](https://github.com/redhat-developer/app-services-cli/issues/1518)) +* remove invalid char in docs +* use default page size from build +* add create support +* add parameters +* improve messages +* add example strings +* add connectors to root +* move messages generator +* default client +* **connector:** hide connector commands +* **connector namespace:** add validation + +### Features + +* initial implementation for connectors commands +* **connector:** add update and namespace commands +* **connector namespace:** add delete command and refactors +* **connectors:** add update cmd and enhance commands +* **service-registry:** display compatibile API endpoints + + + +## [v0.40.1](https://github.com/redhat-developer/app-services-cli/compare/v0.40.0...v0.40.1) (2022-04-20) + +### Bug Fixes + +* disable check for region ([#1527](https://github.com/redhat-developer/app-services-cli/issues/1527)) +* **generate-config:** change keyname to kafkaHost ([#1528](https://github.com/redhat-developer/app-services-cli/issues/1528)) + + + +## [v0.40.0](https://github.com/redhat-developer/app-services-cli/compare/v0.39.0...v0.40.0) (2022-04-12) + +### Bug Fixes + +* include toml files in build ([#1477](https://github.com/redhat-developer/app-services-cli/issues/1477)) +* suspend updating modular docs for prereleases ([#1521](https://github.com/redhat-developer/app-services-cli/issues/1521)) +* regenerate documentation +* status builder lint issues +* refactor status command +* handle custom context location +* rename context maps +* address review comments +* message for partition limit ([#1459](https://github.com/redhat-developer/app-services-cli/issues/1459)) +* add migration to the contexts +* add validation for context create +* build failing at test ([#1469](https://github.com/redhat-developer/app-services-cli/issues/1469)) +* update golang version +* update golang version +* update go in CI/CD workflow ([#1514](https://github.com/redhat-developer/app-services-cli/issues/1514)) +* update telemetry setup +* add server side backed up metrics ([#1493](https://github.com/redhat-developer/app-services-cli/issues/1493)) +* add support for calling any endpoint from control plane ([#1497](https://github.com/redhat-developer/app-services-cli/issues/1497)) +* changes required for Kafka SDK update ([#1470](https://github.com/redhat-developer/app-services-cli/issues/1470)) +* enable self updating CLI ([#1509](https://github.com/redhat-developer/app-services-cli/issues/1509)) +* **context:** fixes bugs and add comments +* **context:** examples of re-used commands +* **deps:** update docusaurus monorepo to v2.0.0-beta.18 +* **deps:** update module github.com/golang-jwt/jwt/v4 to v4.4.0 +* **deps:** update all +* **deps:** update module github.com/golang-jwt/jwt/v4 to v4.4.1 +* **deps:** update module github.com/alecaivazis/survey/v2 to v2.3.4 +* **deps:** update module github.com/alecaivazis/survey/v2 to v2.3.3 +* **deps:** update docusaurus monorepo to v2.0.0-beta.17 +* **deps:** update docusaurus monorepo to v2.0.0-beta.16 +* **deps:** update golang.org/x/oauth2 commit hash to ee48083 + +### Features + +* token command ([#1520](https://github.com/redhat-developer/app-services-cli/issues/1520)) +* alias status and use commands to context cmds +* **context:** add generate-config command +* **context:** add command to delete contexts +* **context:** add command for context creation +* **context:** add commands for context management +* **context create:** remove setting services +* **context status:** show context name and path + + -## [v0.39.0](https://github.com/redhat-developer/app-services-cli/compare/v0.38.6...v0.39.0) (2022-02-21) +## [v0.39.0](https://github.com/redhat-developer/app-services-cli/compare/v0.39.1...v0.39.0) (2022-02-21) + + + +## [v0.39.1](https://github.com/redhat-developer/app-services-cli/compare/v0.38.6...v0.39.1) (2022-02-21) ### Bug Fixes @@ -26,11 +123,7 @@ -## [v0.38.5](https://github.com/redhat-developer/app-services-cli/compare/0.38.5...v0.38.5) (2022-02-15) - - - -## [0.38.5](https://github.com/redhat-developer/app-services-cli/compare/v0.38.4...0.38.5) (2022-02-15) +## [v0.38.5](https://github.com/redhat-developer/app-services-cli/compare/v0.38.4...v0.38.5) (2022-02-15) ### Bug Fixes diff --git a/Makefile b/Makefile index 7a90b00d1..240ea2c11 100644 --- a/Makefile +++ b/Makefile @@ -86,12 +86,12 @@ generate-downstream-docs: ## Generate command-line reference documentation in ad I18N_LINTER_DEF := $(shell command -v app-services-go-linter 2> /dev/null) -lint-lang: ## Lint i18n files -ifndef I18N_LINTER_DEF # check if the linter is installed, install it if not - go install github.com/redhat-developer/app-services-go-linter/cmd/app-services-go-linter@latest -endif - app-services-go-linter -path ./pkg/core/localize/locales ./... -.PHONY: lint-lang +# lint-lang: ## Lint i18n files +# ifndef I18N_LINTER_DEF # check if the linter is installed, install it if not +# go install github.com/redhat-developer/app-services-go-linter/cmd/app-services-go-linter@latest +# endif +# app-services-go-linter -path ./pkg/core/localize/locales ./... +# .PHONY: lint-lang # Check http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html help: diff --git a/USAGE_DATA.md b/USAGE_DATA.md index 0d999a1a6..e0ca36141 100644 --- a/USAGE_DATA.md +++ b/USAGE_DATA.md @@ -14,5 +14,5 @@ Note that these commands do not include `--help` commands. We do not collect dat To disable collection of the usage data please set environment variable in your terminal: ``` -RHOAS_TELEMETRY=true -``` \ No newline at end of file +RHOAS_TELEMETRY=false +``` diff --git a/cmd/rhoas/main.go b/cmd/rhoas/main.go index 489a6c36a..5813f1740 100644 --- a/cmd/rhoas/main.go +++ b/cmd/rhoas/main.go @@ -7,7 +7,9 @@ import ( "strings" "github.com/redhat-developer/app-services-cli/pkg/cmd/root" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/internal/telemetry" "github.com/redhat-developer/app-services-cli/pkg/core/config" @@ -32,12 +34,16 @@ func main() { buildVersion := build.Version cmdFactory := defaultfactory.New(localizer) - err = initConfig(cmdFactory) - if err != nil { + if err = initConfig(cmdFactory); err != nil { cmdFactory.Logger.Errorf(localizer.MustLocalize("main.config.error", localize.NewEntry("Error", err))) os.Exit(1) } + if err = initProfiles(cmdFactory); err != nil { + cmdFactory.Logger.Errorf(localizer.MustLocalize("main.context.error", localize.NewEntry("Error", err))) + os.Exit(1) + } + rootCmd := root.NewRootCommand(cmdFactory, buildVersion) rootCmd.InitDefaultHelpCmd() @@ -87,6 +93,60 @@ func initConfig(f *factory.Factory) error { return nil } +func initProfiles(f *factory.Factory) error { + if !servicecontext.HasCustomLocation() { + rhoasCtxDir, err := config.DefaultDir() + if err != nil { + return err + } + + // create rhoas config directory + if _, err = os.Stat(rhoasCtxDir); os.IsNotExist(err) { + err = os.MkdirAll(rhoasCtxDir, 0o700) + if err != nil { + return err + } + } + } + + ctxFile, err := f.ServiceContext.Load() + + if ctxFile != nil { + return err + } + + if !os.IsNotExist(err) { + return err + } + + configFile, err := f.Config.Load() + + if err != nil { + return err + } + + kafkaId, _ := configFile.GetKafkaIdOk() + serviceRegistryId, _ := configFile.GetServiceRegistryIdOk() + ctxFile = &servicecontext.Context{ + CurrentContext: "default", + Contexts: map[string]servicecontext.ServiceConfig{ + "default": { + KafkaID: kafkaId, + ServiceRegistryID: serviceRegistryId, + }, + }, + } + + if err := f.ServiceContext.Save(ctxFile); err != nil { + return err + } + + configFile.Services = config.ServiceConfigMap{} + _ = f.Config.Save(configFile) + + return nil +} + // rootError creates the root error which is printed to the console // it wraps the error which has been returned from subcommands with a prefix func rootError(err error, localizer localize.Localizer) error { @@ -119,6 +179,10 @@ func executeCommandWithTelemetry(rootCmd *cobra.Command, cmdFactory *factory.Fac if cmd.Runnable() && !cmd.Hidden { commandPath = cmd.CommandPath() } + _, newErr := cmdutil.DoSelfUpdateOnceADay(cmdFactory) + if newErr != nil { + cmdFactory.Logger.Errorf(cmdFactory.Localizer.MustLocalize("main.update.error", localize.NewEntry("Error", newErr))) + } } err = rootCmd.Execute() diff --git a/docs/commands/rhoas.md b/docs/commands/rhoas.md index 2fc015a94..24b5d6648 100644 --- a/docs/commands/rhoas.md +++ b/docs/commands/rhoas.md @@ -36,13 +36,16 @@ $ rhoas cluster connect ### SEE ALSO +* [rhoas authtoken](rhoas_authtoken.md) - Output the current token * [rhoas cluster](rhoas_cluster.md) - View and perform operations on your Kubernetes or OpenShift cluster * [rhoas completion](rhoas_completion.md) - Install command completion for your shell (bash, zsh, or fish) +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services +* [rhoas generate-config](rhoas_generate-config.md) - Generate configurations for the service context * [rhoas kafka](rhoas_kafka.md) - Create, view, use, and manage your Kafka instances * [rhoas login](rhoas_login.md) - Log in to RHOAS * [rhoas logout](rhoas_logout.md) - Log out from RHOAS * [rhoas service-account](rhoas_service-account.md) - Create, list, describe, delete, and update service accounts * [rhoas service-registry](rhoas_service-registry.md) - Service Registry commands -* [rhoas status](rhoas_status.md) - View the status of your application services +* [rhoas status](rhoas_status.md) - View the status of application services in a service context * [rhoas whoami](rhoas_whoami.md) - Output the current username diff --git a/docs/commands/rhoas_authtoken.md b/docs/commands/rhoas_authtoken.md new file mode 100644 index 000000000..362fdbe3e --- /dev/null +++ b/docs/commands/rhoas_authtoken.md @@ -0,0 +1,35 @@ +## rhoas authtoken + +Output the current token + +### Synopsis + +View the authentication token of the current user that can be used to +make general API requests against api.openshift.com APIs. + +This command outputs the token for the user currently logged in. + + +``` +rhoas authtoken [flags] +``` + +### Examples + +``` +# Returns header with token used for authorization +$ echo Authorization: BEARER ${rhoas authtoken} + +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas](rhoas.md) - RHOAS CLI + diff --git a/docs/commands/rhoas_context.md b/docs/commands/rhoas_context.md new file mode 100644 index 000000000..94e0323b4 --- /dev/null +++ b/docs/commands/rhoas_context.md @@ -0,0 +1,57 @@ +## rhoas context + +Group, share and manage your rhoas services + +### Synopsis + +Group your service instances into reusable contexts. +Context can be used when running other rhoas commands or to generate service configuration. + +A service context is a group of application service instances and their service identifiers. By using service contexts, you can group together application service instances that you want to use together. + +After creating a service context, you can share it with other developers so that they can use the same group of application service instances. + +You can also use the service context to automatically generate configuration files that you need to use those application service instances in other development platforms and tools. For example, the service context can generate the following types of configurations: + +- Standard environment variables for use in local development and tooling +- Java properties files that can be used in Quarkus, Apache Kafka, and so on +- Service binding configuration and service connections for the RHOAS Operator +- Configuration for Helm Charts and Kubernetes + +The service context is defined in a JSON file (`contexts.json`), and stored locally on your computer. To find the location of this file, use the "rhoas context status" command. + +Note: To specify a custom location for the `contexts.json` file, set the $RHOAS_CONTEXT environment variable to the location you want to use. If you set $RHOAS_CONTEXT to "./rhoas.json", service contexts will be loaded from the current directory. + + +### Examples + +``` +# Set the current context +$ rhoas context use --name qa + +# List contexts +$ rhoas context list + +# Create a context to represent a group of development services +$ rhoas context create --name dev-env + +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas](rhoas.md) - RHOAS CLI +* [rhoas context create](rhoas_context_create.md) - Create a service context +* [rhoas context delete](rhoas_context_delete.md) - Permanently delete a service context. +* [rhoas context list](rhoas_context_list.md) - List service contexts +* [rhoas context status](rhoas_context_status.md) - View the status of application services in a service context +* [rhoas context use](rhoas_context_use.md) - Set the current context +* [rhoas context use-kafka](rhoas_context_use-kafka.md) - Set the current Kafka instance +* [rhoas context use-service-registry](rhoas_context_use-service-registry.md) - Use a Service Registry instance + diff --git a/docs/commands/rhoas_context_create.md b/docs/commands/rhoas_context_create.md new file mode 100644 index 000000000..3e086017f --- /dev/null +++ b/docs/commands/rhoas_context_create.md @@ -0,0 +1,42 @@ +## rhoas context create + +Create a service context + +### Synopsis + +Create a service context and assign associated service identifiers. + +A service context is a group of application service instances and their configuration details. By creating a service context, you can group together application service instances that you want to use together. + +After creating the service context, add application service instances to it by using the "rhoas context use-[service]" commands. + + +``` +rhoas context create [flags] +``` + +### Examples + +``` +# Create context +$ rhoas context create --name dev + +``` + +### Options + +``` + --name string Name of the context +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_delete.md b/docs/commands/rhoas_context_delete.md new file mode 100644 index 000000000..bf94054d1 --- /dev/null +++ b/docs/commands/rhoas_context_delete.md @@ -0,0 +1,40 @@ +## rhoas context delete + +Permanently delete a service context. + +### Synopsis + +Delete a service context. + +``` +rhoas context delete [flags] +``` + +### Examples + +``` +# Delete the currently-selected service context +$ rhoas context delete + +# Delete a service context by name +$ rhoas context delete --name dev + +``` + +### Options + +``` + --name string Name of the context +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_list.md b/docs/commands/rhoas_context_list.md new file mode 100644 index 000000000..fea8e1ccf --- /dev/null +++ b/docs/commands/rhoas_context_list.md @@ -0,0 +1,40 @@ +## rhoas context list + +List service contexts + +### Synopsis + +List all service contexts. This command lists each service context, and indicates the context that is currently being used. + +To view the details of a service context, use the "rhoas context status" command. + + +``` +rhoas context list [flags] +``` + +### Examples + +``` +# List contexts +$ rhoas context list + +``` + +### Options + +``` + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_status.md b/docs/commands/rhoas_context_status.md new file mode 100644 index 000000000..dd0364847 --- /dev/null +++ b/docs/commands/rhoas_context_status.md @@ -0,0 +1,52 @@ +## rhoas context status + +View the status of application services in a service context + +### Synopsis + +View the status of your application services. This command shows the status of each of the application services instances in the service context. + +To view the status of a specific application service, use "rhoas context status [service]". + +Note: You can change the current instance for an application service with the "rhoas [service] use” command. + + +``` +rhoas context status [args] [flags] +``` + +### Examples + +``` +# View the status of all application services in the current service context +$ rhoas context status + +# View the status of all application services in a specific service context +$ rhoas context status --name my-context + +# View the status of the Kafka instance set in the current service context +$ rhoas context status kafka + +# View the status of your services in JSON format +$ rhoas context status -o json + +``` + +### Options + +``` + --name string Name of the context + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_use-kafka.md b/docs/commands/rhoas_context_use-kafka.md new file mode 100644 index 000000000..dda9e01dc --- /dev/null +++ b/docs/commands/rhoas_context_use-kafka.md @@ -0,0 +1,44 @@ +## rhoas context use-kafka + +Set the current Kafka instance + +### Synopsis + +Select a Kafka instance to be the current instance. When you set the Kafka instance to be used, it is set as the current instance for all “rhoas kafka topic” and “rhoas kafka consumer-group” commands. + +You can select a Kafka instance by name or ID. + + +``` +rhoas context use-kafka [flags] +``` + +### Examples + +``` +# Select a Kafka instance by name to be set in the current context +$ rhoas context use-kafka --name=my-kafka + +# Select a Kafka instance by ID to be set in the current context +$ rhoas context use-kafka --id=1iSY6RQ3JKI8Q0OTmjQFd3ocFRg + +``` + +### Options + +``` + --id string Unique ID of the Kafka instance you want to set as the current instance + --name string Name of the Kafka instance you want to set as the current instance +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_use-service-registry.md b/docs/commands/rhoas_context_use-service-registry.md new file mode 100644 index 000000000..a02fbcb9a --- /dev/null +++ b/docs/commands/rhoas_context_use-service-registry.md @@ -0,0 +1,45 @@ +## rhoas context use-service-registry + +Use a Service Registry instance + +### Synopsis + +Select a Service Registry instance to use with all instance-specific commands. +You can specify a Service Registry instance by --name or --id. + +When you set the Service Registry instance to be used, it is set as the current instance for all rhoas service-registry artifact commands. + + +``` +rhoas context use-service-registry [flags] +``` + +### Examples + +``` +# Select a Service Registry instance by name to be set in the current context +rhoas context use-service-registry --name my-service-registry + +# Select a Service Registry instance by ID to be set in the current context +rhoas context use-service-registry --id 1iSY6RQ3JKI8Q0OTmjQFd3ocFRg + +``` + +### Options + +``` + --id string Unique ID of the Service Registry instance you want to set as the current instance + --name string Name the Service Registry instance you want to set as the current instance +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_context_use.md b/docs/commands/rhoas_context_use.md new file mode 100644 index 000000000..ea36ddd50 --- /dev/null +++ b/docs/commands/rhoas_context_use.md @@ -0,0 +1,40 @@ +## rhoas context use + +Set the current context + +### Synopsis + +Select a service context to be used as the current context. + +When you set the context to be used, it is set as the current context for all service-based rhoas commands. + + +``` +rhoas context use [flags] +``` + +### Examples + +``` +# Set the current context +$ rhoas context use --name dev + +``` + +### Options + +``` + --name string Name of the context +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas context](rhoas_context.md) - Group, share and manage your rhoas services + diff --git a/docs/commands/rhoas_generate-config.md b/docs/commands/rhoas_generate-config.md new file mode 100644 index 000000000..ee49da7d7 --- /dev/null +++ b/docs/commands/rhoas_generate-config.md @@ -0,0 +1,38 @@ +## rhoas generate-config + +Generate configurations for the service context + +### Synopsis + +Generate configuration files for the service context to connect with to be used with various tools and platforms + +``` +rhoas generate-config [flags] +``` + +### Examples + +``` +## Generate configurations for the current service context in json format +$ rhoas generate-config --type json + +``` + +### Options + +``` + --name string Name of the context + --type string Type of configuration file to be generated +``` + +### Options inherited from parent commands + +``` + -h, --help Show help for a command + -v, --verbose Enable verbose mode +``` + +### SEE ALSO + +* [rhoas](rhoas.md) - RHOAS CLI + diff --git a/docs/commands/rhoas_kafka_acl_create.md b/docs/commands/rhoas_kafka_acl_create.md index 0f6615384..4c9ef36f6 100644 --- a/docs/commands/rhoas_kafka_acl_create.md +++ b/docs/commands/rhoas_kafka_acl_create.md @@ -30,7 +30,7 @@ $ rhoas kafka acl create --operation all --permission allow --group "group-1" -- --all-accounts Set the ACL principal to match all principals (users and service accounts) --cluster Set the resource type to cluster --group string Set the consumer group resource. When the --prefix option is also passed, this is used as the consumer group prefix - --instance-id string Kafka instance ID. Uses the current instance if not set + --instance-id string Kafka instance ID. Uses the current instance if not set --operation string Set the ACL operation. Choose from: "all", "alter", "alter-configs", "create", "delete", "describe", "describe-configs", "read", "write" --permission string Set the ACL permission. Choose from: "allow", "deny" --prefix Determine if the resource should be exact match or prefix diff --git a/docs/commands/rhoas_kafka_acl_delete.md b/docs/commands/rhoas_kafka_acl_delete.md index 45e7b3ed1..4def93c4b 100644 --- a/docs/commands/rhoas_kafka_acl_delete.md +++ b/docs/commands/rhoas_kafka_acl_delete.md @@ -33,9 +33,9 @@ $ rhoas kafka acl delete --operation all --permission any --group "group-1" --al --all-accounts Set the ACL principal to match all principals (users and service accounts) --cluster Set the resource type to cluster --group string Set the consumer group resource. When the --prefix option is also passed, this is used as the consumer group prefix - --instance-id string Kafka instance ID. Uses the current instance if not set + --instance-id string Kafka instance ID. Uses the current instance if not set --operation string Set the ACL operation. Choose from: "all", "alter", "alter-configs", "create", "delete", "describe", "describe-configs", "read", "write" - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") --pattern-type string Allows to specify arguments matching strategy [any literal prefix] (default "literal") --permission string Set the ACL permission. Choose from: "allow", "any", "deny" (default "any") --prefix Determine if the resource should be exact match or prefix diff --git a/docs/commands/rhoas_kafka_acl_grant-access.md b/docs/commands/rhoas_kafka_acl_grant-access.md index 66f4d88ce..4f4eec5ea 100644 --- a/docs/commands/rhoas_kafka_acl_grant-access.md +++ b/docs/commands/rhoas_kafka_acl_grant-access.md @@ -46,7 +46,7 @@ $ rhoas kafka acl grant-access --producer --consumer --user user_name --topic al --consumer Add ACL rules that grant the specified principal access to consume messages from topics --group string Consumer group ID to define ACL rules for --group-prefix string Prefix name for groups to be selected - --instance-id string Kafka instance ID. Uses the current instance if not set + --instance-id string Kafka instance ID. Uses the current instance if not set --producer Add ACL rules that grant the specified principal access to produce messages to topics --service-account string Service account client ID used as principal for this operation --topic string Topic name to define ACL rules for diff --git a/docs/commands/rhoas_kafka_acl_grant-admin.md b/docs/commands/rhoas_kafka_acl_grant-admin.md index 8c711d342..dd25da35c 100644 --- a/docs/commands/rhoas_kafka_acl_grant-admin.md +++ b/docs/commands/rhoas_kafka_acl_grant-admin.md @@ -28,7 +28,7 @@ $ rhoas kafka acl grant-admin --all-accounts --instance-id c5hv7iru4an1g84pogp0 ``` --all-accounts Set the ACL principal to match all principals (users and service accounts) - --instance-id string Kafka instance ID. Uses the current instance if not set + --instance-id string Kafka instance ID. Uses the current instance if not set --service-account string Service account client ID used as principal for this operation --user string User ID to be used as principal -y, --yes Skip confirmation of this action diff --git a/docs/commands/rhoas_kafka_acl_list.md b/docs/commands/rhoas_kafka_acl_list.md index 5ed661ea7..244c7e38f 100644 --- a/docs/commands/rhoas_kafka_acl_list.md +++ b/docs/commands/rhoas_kafka_acl_list.md @@ -55,8 +55,8 @@ $ rhoas kafka acl list --group foo_group_id --user foo_user --all-accounts Set the ACL principal to match all principals (users and service accounts) --cluster Set filter to cluster resource --group string Text search to filter ACL rules for consumer groups by ID - --instance-id string Kafka instance ID. Uses the current instance if not set - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + --instance-id string Kafka instance ID. Uses the current instance if not set + -o, --output string Specify the output format. Choose from: "json", "none", "table", "yaml", "yml" (default "table") --page int32 Current page number for the list (default 1) --service-account string Service account client ID used as principal for this operation --size int32 Maximum number of items to be returned per page (default 10) diff --git a/docs/commands/rhoas_kafka_consumer-group_delete.md b/docs/commands/rhoas_kafka_consumer-group_delete.md index 53a7f4984..cb218fda8 100644 --- a/docs/commands/rhoas_kafka_consumer-group_delete.md +++ b/docs/commands/rhoas_kafka_consumer-group_delete.md @@ -24,8 +24,9 @@ $ rhoas kafka consumer-group delete --id consumer_group_1 ### Options ``` - --id string The unique ID of the consumer group to delete - -y, --yes Skip confirmation of this action + --id string The unique ID of the consumer group to delete + --instance-id string Kafka instance ID. Uses the current instance if not set + -y, --yes Skip confirmation of this action ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_consumer-group_describe.md b/docs/commands/rhoas_kafka_consumer-group_describe.md index 614b6a885..ae56ceedb 100644 --- a/docs/commands/rhoas_kafka_consumer-group_describe.md +++ b/docs/commands/rhoas_kafka_consumer-group_describe.md @@ -23,7 +23,7 @@ $ rhoas kafka consumer-group describe --id consumer_group_1 -o json ``` --id string The unique ID of the consumer group to view - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_consumer-group_list.md b/docs/commands/rhoas_kafka_consumer-group_list.md index 243124d5d..d152fc99f 100644 --- a/docs/commands/rhoas_kafka_consumer-group_list.md +++ b/docs/commands/rhoas_kafka_consumer-group_list.md @@ -24,11 +24,12 @@ $ rhoas kafka consumer-group list -o json ### Options ``` - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" - --page int32 View the specified page number in the list of consumer groups (default 1) - --search string Text search to filter consumer groups by ID - --size int32 Maximum number of consumer groups to be returned per page (default 10) - --topic string Fetch the consumer groups for a specific Kafka topic + --instance-id string Kafka instance ID. Uses the current instance if not set + -o, --output string Specify the output format. Choose from: "json", "none", "table", "yaml", "yml" (default "table") + --page int32 View the specified page number in the list of consumer groups (default 1) + --search string Text search to filter consumer groups by ID + --size int32 Maximum number of consumer groups to be returned per page (default 10) + --topic string Fetch the consumer groups for a specific Kafka topic ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_consumer-group_reset-offset.md b/docs/commands/rhoas_kafka_consumer-group_reset-offset.md index d740dd4a2..bfa5183a5 100644 --- a/docs/commands/rhoas_kafka_consumer-group_reset-offset.md +++ b/docs/commands/rhoas_kafka_consumer-group_reset-offset.md @@ -45,6 +45,7 @@ $ rhoas kafka consumer-group reset-offset --id consumer_group_1 --topic my-topic ``` --id string The unique ID of the consumer group to reset-offset + --instance-id string Kafka instance ID. Uses the current instance if not set --offset string Offset type (choose from: "earliest", "latest", "absolute", "timestamp") --partitions int32Slice Reset consumer group offsets on specified partitions (comma-separated integers) (default []) --topic string Reset consumer group offsets on a specified topic diff --git a/docs/commands/rhoas_kafka_create.md b/docs/commands/rhoas_kafka_create.md index 3756005ee..1445e51b7 100644 --- a/docs/commands/rhoas_kafka_create.md +++ b/docs/commands/rhoas_kafka_create.md @@ -31,7 +31,7 @@ $ rhoas kafka create -o yaml ``` --name string Unique name of the Kafka instance - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") --provider string Cloud Provider ID --region string Cloud Provider Region ID --use Set the new Kafka instance to the current instance (default true) diff --git a/docs/commands/rhoas_kafka_describe.md b/docs/commands/rhoas_kafka_describe.md index 5d74d00cf..a56d0c1a1 100644 --- a/docs/commands/rhoas_kafka_describe.md +++ b/docs/commands/rhoas_kafka_describe.md @@ -42,7 +42,7 @@ $ rhoas kafka describe -o yaml --bootstrap-server If specified, only the bootstrap server host of the Kafka instance will be displayed --id string Unique ID of the Kafka instance you want to view --name string Name of the Kafka instance you want to view - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_list.md b/docs/commands/rhoas_kafka_list.md index b85fe3837..8a789963c 100644 --- a/docs/commands/rhoas_kafka_list.md +++ b/docs/commands/rhoas_kafka_list.md @@ -30,7 +30,7 @@ $ rhoas kafka list -o json ``` --limit int The maximum number of Kafka instances to be returned (default 100) - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "table", "yaml", "yml" (default "table") --page int Display the Kafka instances from the specified page number (default 1) --search string Text search to filter the Kafka instances by name, owner, cloud_provider, region and status ``` diff --git a/docs/commands/rhoas_kafka_topic_create.md b/docs/commands/rhoas_kafka_topic_create.md index 5653b2ef2..dedf0c50b 100644 --- a/docs/commands/rhoas_kafka_topic_create.md +++ b/docs/commands/rhoas_kafka_topic_create.md @@ -25,8 +25,9 @@ $ rhoas kafka topic create --name topic-1 ``` --cleanup-policy string Determines whether log messages are deleted, compacted, or both (default "delete") + --instance-id string Kafka instance ID. Uses the current instance if not set --name string Topic name - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") --partitions int32 The number of partitions in the topic (default 1) --retention-bytes int The maximum total size of a partition log segments before old log segments are deleted to free up space. Value of -1 is set by default indicating no retention size limits (default -1) diff --git a/docs/commands/rhoas_kafka_topic_delete.md b/docs/commands/rhoas_kafka_topic_delete.md index 1e8371f26..78d0e69b9 100644 --- a/docs/commands/rhoas_kafka_topic_delete.md +++ b/docs/commands/rhoas_kafka_topic_delete.md @@ -22,8 +22,9 @@ $ rhoas kafka topic delete --name topic-1 ### Options ``` - --name string Topic name - -y, --yes Skip confirmation of this action + --instance-id string Kafka instance ID. Uses the current instance if not set + --name string Topic name + -y, --yes Skip confirmation of this action ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_topic_describe.md b/docs/commands/rhoas_kafka_topic_describe.md index 11bb25b37..ced07a1ed 100644 --- a/docs/commands/rhoas_kafka_topic_describe.md +++ b/docs/commands/rhoas_kafka_topic_describe.md @@ -22,8 +22,9 @@ $ rhoas kafka topic describe --name topic-1 ### Options ``` - --name string Format in which to display the Kafka topic (choose from: "json", "yml", "yaml") - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + --instance-id string Kafka instance ID. Uses the current instance if not set + --name string Format in which to display the Kafka topic (choose from: "json", "yml", "yaml") + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") ``` ### Options inherited from parent commands diff --git a/docs/commands/rhoas_kafka_topic_list.md b/docs/commands/rhoas_kafka_topic_list.md index fadbc7419..cf86d1c20 100644 --- a/docs/commands/rhoas_kafka_topic_list.md +++ b/docs/commands/rhoas_kafka_topic_list.md @@ -25,7 +25,7 @@ $ rhoas kafka topic list -o json ### Options ``` - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "table", "yaml", "yml" (default "table") --page int32 Current page number for list of topics (default 1) --search string Text search to filter the Kafka topics by name --size int32 Maximum number of items to be returned per page (default 10) diff --git a/docs/commands/rhoas_kafka_topic_update.md b/docs/commands/rhoas_kafka_topic_update.md index 960be25aa..0f71f536e 100644 --- a/docs/commands/rhoas_kafka_topic_update.md +++ b/docs/commands/rhoas_kafka_topic_update.md @@ -23,6 +23,7 @@ $ rhoas kafka topic update --name topic-1 --retention-ms -1 ``` --cleanup-policy string Determines whether log messages are deleted, compacted, or both + --instance-id string Kafka instance ID. Uses the current instance if not set --name string Topic name --partitions string The number of partitions in the topic --retention-bytes string The maximum total size of a partition log segments before old log segments are deleted to free up space. diff --git a/docs/commands/rhoas_kafka_use.md b/docs/commands/rhoas_kafka_use.md index f52a0ddc6..36338642d 100644 --- a/docs/commands/rhoas_kafka_use.md +++ b/docs/commands/rhoas_kafka_use.md @@ -16,10 +16,10 @@ rhoas kafka use [flags] ### Examples ``` -# Select a Kafka instance to be the current instance +# Select a Kafka instance by name to be set in the current context $ rhoas kafka use --name=my-kafka -# Select a Kafka instance to be the current instance +# Select a Kafka instance by ID to be set in the current context $ rhoas kafka use --id=1iSY6RQ3JKI8Q0OTmjQFd3ocFRg ``` diff --git a/docs/commands/rhoas_service-registry_rule_describe.md b/docs/commands/rhoas_service-registry_rule_describe.md index 6119588e7..843ff63de 100644 --- a/docs/commands/rhoas_service-registry_rule_describe.md +++ b/docs/commands/rhoas_service-registry_rule_describe.md @@ -27,7 +27,7 @@ $ rhoas service-registry rule describe --rule-type=compatibility --artifact-id=m --artifact-id string ID of the artifact -g, --group string Artifact group (default "default") --instance-id string ID of the Service Registry instance to be used (by default, uses the currently selected instance) - -o, --output string Specify the output format. Choose from: "json", "yaml", "yml" + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") --rule-type string Rule type determines how the content of an artifact can evolve over time ``` diff --git a/docs/commands/rhoas_status.md b/docs/commands/rhoas_status.md index cf4b13baa..8e6fd50e6 100644 --- a/docs/commands/rhoas_status.md +++ b/docs/commands/rhoas_status.md @@ -1,10 +1,10 @@ ## rhoas status -View the status of your application services +View the status of application services in a service context ### Synopsis -View the status of your application services. This command shows the status of the current instance for each of your application services. +View the status of your application services. This command shows the status of each of your application services instances that belong to a service context. To view the status of a specific application service, use "rhoas status [service]". @@ -18,10 +18,10 @@ rhoas status [args] [flags] ### Examples ``` -# View the status of all application services +# View the status of all application services in the current service context $ rhoas status -# View the status of the current Kafka instance +# View the status of all application services in a specific service context $ rhoas status kafka # View the status of your services in JSON format @@ -32,7 +32,8 @@ $ rhoas status -o json ### Options ``` - -o, --output string Format in which to display the status of your services (choose from: "json", "yml", "yaml") + --name string Name of the context + -o, --output string Specify the output format. Choose from: "json", "none", "yaml", "yml" (default "json") ``` ### Options inherited from parent commands diff --git a/go.mod b/go.mod index 4af513032..21fab0062 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,11 @@ go 1.16 require ( github.com/AlecAivazis/survey/v2 v2.3.4 - github.com/BurntSushi/toml v1.0.0 + github.com/BurntSushi/toml v1.1.0 github.com/MakeNowJust/heredoc v1.0.0 github.com/Nerzal/gocloak/v7 v7.11.0 github.com/aerogear/charmil v0.8.3 + github.com/blang/semver v3.5.1+incompatible github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/briandowns/spinner v1.18.1 github.com/coreos/go-oidc/v3 v3.1.0 @@ -23,6 +24,7 @@ require ( github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/pkg/errors v0.9.1 github.com/redhat-developer/app-services-sdk-go/accountmgmt v0.1.0 + github.com/redhat-developer/app-services-sdk-go/connectormgmt v0.5.0 github.com/redhat-developer/app-services-sdk-go/kafkainstance v0.6.0 github.com/redhat-developer/app-services-sdk-go/kafkamgmt v0.9.0 github.com/redhat-developer/app-services-sdk-go/registryinstance v0.3.1 @@ -31,11 +33,16 @@ require ( github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/wtrocki/go-github-selfupdate v1.2.4 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a + golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b // indirect golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a golang.org/x/text v0.3.7 golang.org/x/tools v0.1.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.22.4 diff --git a/go.sum b/go.sum index b5ecf7def..ed8572217 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,9 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= @@ -120,6 +121,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= @@ -355,8 +357,11 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= +github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ= github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -438,6 +443,8 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= +github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= @@ -563,6 +570,7 @@ github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= @@ -628,6 +636,8 @@ github.com/redhat-developer/app-services-sdk-go v0.10.0 h1:zI0X5FR0NOj6IwBWk3y1T github.com/redhat-developer/app-services-sdk-go v0.10.0/go.mod h1:enn8Zz6IT0HZYzS6LSttiME2apwnvfVWZnGRS81A4rk= github.com/redhat-developer/app-services-sdk-go/accountmgmt v0.1.0 h1:MOljVN8AKTM72Yed8ioAwhdW0KdWEhBZjjam3lY2lyY= github.com/redhat-developer/app-services-sdk-go/accountmgmt v0.1.0/go.mod h1:0LX7ZCEmMKAbncO05/zRYsV0K5wsds7AGPpOFC7KWGo= +github.com/redhat-developer/app-services-sdk-go/connectormgmt v0.5.0 h1:cf+K96kW8o6v6JSzaGpQI5amEzSJuGrd5on3V+SmKhg= +github.com/redhat-developer/app-services-sdk-go/connectormgmt v0.5.0/go.mod h1:JAedrXf/qLHd7lpOS+bOFh8nrOpp2j0sg4/VG/1um6c= github.com/redhat-developer/app-services-sdk-go/kafkainstance v0.6.0 h1:ExEHQaihnPNxN2nKXB0q5nrmSv4p8b3Idzt7TChxv+Q= github.com/redhat-developer/app-services-sdk-go/kafkainstance v0.6.0/go.mod h1:hMpejngP3BFnifCDH1gKRG9cU9Q4lr0WiQaW7A1LYo4= github.com/redhat-developer/app-services-sdk-go/kafkamgmt v0.9.0 h1:wb335WbgyhFZRIHOwqHJm+D877l50MPMacrONCmknnw= @@ -704,6 +714,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= +github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -714,8 +726,13 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/wtrocki/go-github-selfupdate v1.2.4 h1:dFm8Ge+wHJ3ahS3OE05tsNI6w+W/YdJre7k2dNO6uMk= +github.com/wtrocki/go-github-selfupdate v1.2.4/go.mod h1:sXGbZniTJbQoWzXGdfVTgPWLEBEq5SX6jxO7q+J7ymo= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -797,11 +814,13 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -894,9 +913,12 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1125,6 +1147,7 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -1210,8 +1233,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/cmd/cluster/bind/bind.go b/pkg/cmd/cluster/bind/bind.go index 6bc4fbc15..63b8f9b18 100644 --- a/pkg/cmd/cluster/bind/bind.go +++ b/pkg/cmd/cluster/bind/bind.go @@ -3,10 +3,10 @@ package bind import ( "context" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" @@ -18,12 +18,12 @@ import ( ) type options struct { - Config config.IConfig - Connection func(connectionCfg *connection.Config) (connection.Connection, error) - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context + Connection func(connectionCfg *connection.Config) (connection.Connection, error) + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext kubeconfigLocation string namespace string @@ -41,12 +41,12 @@ type options struct { func NewBindCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -99,12 +99,12 @@ func runBind(opts *options) error { } cliProperties := v1alpha.CommandEnvironment{ - IO: opts.IO, - Logger: opts.Logger, - Localizer: opts.localizer, - Config: opts.Config, - Connection: conn, - Context: opts.Context, + IO: opts.IO, + Logger: opts.Logger, + Localizer: opts.localizer, + Connection: conn, + Context: opts.Context, + ServiceContext: opts.ServiceContext, } kubeClients, err := kubeclient.NewKubernetesClusterClients(&cliProperties, opts.kubeconfigLocation) diff --git a/pkg/cmd/cluster/clean/clean.go b/pkg/cmd/cluster/clean/clean.go index ee7300acd..5c43895dd 100644 --- a/pkg/cmd/cluster/clean/clean.go +++ b/pkg/cmd/cluster/clean/clean.go @@ -3,10 +3,10 @@ package clean import ( "context" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" @@ -20,12 +20,13 @@ import ( ) type options struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + kubeconfig string namespace string forceCreationWithoutAsk bool @@ -33,7 +34,6 @@ type options struct { func NewCleanCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, Connection: f.Connection, Logger: f.Logger, IO: f.IOStreams, @@ -65,12 +65,12 @@ func runStatus(opts *options) error { } env := v1alpha.CommandEnvironment{ - IO: opts.IO, - Logger: opts.Logger, - Localizer: opts.localizer, - Config: opts.Config, - Connection: conn, - Context: opts.Context, + IO: opts.IO, + Logger: opts.Logger, + Localizer: opts.localizer, + ServiceContext: opts.ServiceContext, + Connection: conn, + Context: opts.Context, } kubeClients, err := kubeclient.NewKubernetesClusterClients(&env, opts.kubeconfig) diff --git a/pkg/cmd/cluster/connect/connect.go b/pkg/cmd/cluster/connect/connect.go index fbca68db0..a15688d54 100644 --- a/pkg/cmd/cluster/connect/connect.go +++ b/pkg/cmd/cluster/connect/connect.go @@ -4,10 +4,10 @@ import ( "context" "github.com/redhat-developer/app-services-cli/internal/build" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" @@ -19,12 +19,12 @@ import ( ) type options struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext kubeconfigLocation string namespace string @@ -38,12 +38,12 @@ type options struct { func NewConnectCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -79,12 +79,12 @@ func runConnect(opts *options) error { } cliProperties := v1alpha.CommandEnvironment{ - IO: opts.IO, - Logger: opts.Logger, - Localizer: opts.localizer, - Config: opts.Config, - Connection: conn, - Context: opts.Context, + IO: opts.IO, + Logger: opts.Logger, + Localizer: opts.localizer, + Connection: conn, + Context: opts.Context, + ServiceContext: opts.ServiceContext, } kubeClients, err := kubeclient.NewKubernetesClusterClients(&cliProperties, opts.kubeconfigLocation) diff --git a/pkg/cmd/cluster/status/status.go b/pkg/cmd/cluster/status/status.go index 8e15ce87f..263d00960 100644 --- a/pkg/cmd/cluster/status/status.go +++ b/pkg/cmd/cluster/status/status.go @@ -4,11 +4,11 @@ import ( "context" "fmt" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" @@ -21,23 +21,23 @@ import ( ) type options struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context - kubeconfig string + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + kubeconfig string } func NewStatusCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -63,12 +63,12 @@ func runStatus(opts *options) error { } cliProperties := v1alpha.CommandEnvironment{ - IO: opts.IO, - Logger: opts.Logger, - Localizer: opts.localizer, - Config: opts.Config, - Connection: conn, - Context: opts.Context, + IO: opts.IO, + Logger: opts.Logger, + Localizer: opts.localizer, + Connection: conn, + Context: opts.Context, + ServiceContext: opts.ServiceContext, } kubeClients, err := kubeclient.NewKubernetesClusterClients(&cliProperties, opts.kubeconfig) diff --git a/pkg/cmd/connector/cluster/addon/addon-parameters.go b/pkg/cmd/connector/cluster/addon/addon-parameters.go new file mode 100644 index 000000000..a4d18dee3 --- /dev/null +++ b/pkg/cmd/connector/cluster/addon/addon-parameters.go @@ -0,0 +1,100 @@ +package addon + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/spf13/cobra" +) + +// row is the details of the addon parameters needed to print to a table +type itemRow struct { + ID string `json:"id" header:"ID"` + Value string `json:"value" header:"Value"` +} + +type options struct { + outputFormat string + id string + + f *factory.Factory +} + +// NewParametersCommand creates a new command to list addon parameters of a connector cluster +func NewParametersCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "addon-parameters", + Short: f.Localizer.MustLocalize("connector.cluster.addonParams.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cluster.addonParams.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cluster.addonParams.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + + return runList(opts) + }, + } + + flags := connectorcmdutil.NewFlagSet(cmd, f) + + flags.AddOutput(&opts.outputFormat) + _ = flags.AddConnectorID(&opts.id).Required() + + return cmd +} + +func runList(opts *options) error { + f := opts.f + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorClustersApi.GetConnectorClusterAddonParameters(f.Context, opts.id) + + response, _, err := a.Execute() + if err != nil { + return err + } + + switch opts.outputFormat { + case dump.EmptyFormat: + rows := mapResponseItemsToRows(response) + + dump.Table(f.IOStreams.Out, rows) + f.Logger.Info("") + return nil + default: + return dump.Formatted(f.IOStreams.Out, opts.outputFormat, response) + } + +} + +func mapResponseItemsToRows(items []connectormgmtclient.AddonParameter) []itemRow { + rows := make([]itemRow, len(items)) + + for i := range items { + k := items[i] + + row := itemRow{ + ID: k.GetId(), + Value: k.GetValue(), + } + + rows[i] = row + } + + return rows +} diff --git a/pkg/cmd/connector/cluster/cluster.go b/pkg/cmd/connector/cluster/cluster.go new file mode 100644 index 000000000..337bb78b5 --- /dev/null +++ b/pkg/cmd/connector/cluster/cluster.go @@ -0,0 +1,31 @@ +package cluster + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/cluster/addon" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/cluster/create" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/cluster/delete" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/cluster/list" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +// NewConnectorClusterCommand creates a new command to manage connector clusters +func NewConnectorClusterCommand(f *factory.Factory) *cobra.Command { + cmd := &cobra.Command{ + Use: "cluster", + Short: f.Localizer.MustLocalize("connector.cluster.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cluster.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cluster.cmd.example"), + Args: cobra.MinimumNArgs(1), + } + + // add sub-commands + cmd.AddCommand( + create.NewCreateCommand(f), + delete.NewDeleteCommand(f), + list.NewListCommand(f), + addon.NewParametersCommand(f), + ) + + return cmd +} diff --git a/pkg/cmd/connector/cluster/create/create.go b/pkg/cmd/connector/cluster/create/create.go new file mode 100644 index 000000000..c80b4b80f --- /dev/null +++ b/pkg/cmd/connector/cluster/create/create.go @@ -0,0 +1,84 @@ +package create + +import ( + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/spf13/cobra" +) + +type options struct { + name string + + outputFormat string + f *factory.Factory +} + +// NewCreateCommand creates a new command to create a connector cluster +func NewCreateCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "create", + Short: f.Localizer.MustLocalize("connector.cluster.create.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cluster.create.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cluster.create.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runCreate(opts) + }, + } + flags := flagutil.NewFlagSet(cmd, f.Localizer) + flags.StringVar(&opts.name, "name", "", f.Localizer.MustLocalize("connector.cluster.create.flag.name.description")) + flags.AddOutput(&opts.outputFormat) + + _ = cmd.MarkFlagRequired("name") + + return cmd +} + +func runCreate(opts *options) error { + f := opts.f + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorClustersApi.CreateConnectorCluster(f.Context) + a = a.ConnectorClusterRequest(connectormgmtclient.ConnectorClusterRequest{ + Name: &opts.name, + }) + a = a.Async(true) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.cluster.create.info.success")) + + return nil +} diff --git a/pkg/cmd/connector/cluster/delete/delete.go b/pkg/cmd/connector/cluster/delete/delete.go new file mode 100644 index 000000000..8377afa20 --- /dev/null +++ b/pkg/cmd/connector/cluster/delete/delete.go @@ -0,0 +1,115 @@ +package delete + +import ( + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/spf13/cobra" +) + +type options struct { + id string + outputFormat string + + f *factory.Factory + skipConfirm bool +} + +// NewDeleteCommand creates a new command to delete a connector cluster +func NewDeleteCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "delete", + Short: f.Localizer.MustLocalize("connector.cluster.delete.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cluster.delete.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cluster.delete.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + if !f.IOStreams.CanPrompt() && !opts.skipConfirm { + return flagutil.RequiredWhenNonInteractiveError("yes") + } + + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runDelete(opts) + }, + } + flags := flagutil.NewFlagSet(cmd, f.Localizer) + flags.StringVar(&opts.id, "id", "", f.Localizer.MustLocalize("connector.cluster.delete.id.flag.description")) + flags.AddOutput(&opts.outputFormat) + flags.AddYes(&opts.skipConfirm) + + _ = cmd.MarkFlagRequired("id") + + return cmd +} + +func runDelete(opts *options) error { + f := opts.f + + if !opts.skipConfirm { + confirm, promptErr := promptConfirmDelete(opts) + if promptErr != nil { + return promptErr + } + if !confirm { + opts.f.Logger.Debug("User has chosen to not delete connector cluster") + return nil + } + } + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorClustersApi.CreateConnectorCluster(f.Context) + a = a.ConnectorClusterRequest(connectormgmtclient.ConnectorClusterRequest{ + Name: &opts.id, + }) + a = a.Async(true) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.cluster.delete.info.success")) + + return nil +} + +func promptConfirmDelete(opts *options) (bool, error) { + promptConfirm := survey.Confirm{ + Message: opts.f.Localizer.MustLocalize("connector.cluster.delete.confirmDialog.message", localize.NewEntry("ID", opts.id)), + } + + var confirmUpdate bool + if err := survey.AskOne(&promptConfirm, &confirmUpdate); err != nil { + return false, err + } + return confirmUpdate, nil +} diff --git a/pkg/cmd/connector/cluster/list/list.go b/pkg/cmd/connector/cluster/list/list.go new file mode 100644 index 000000000..b1f306dfa --- /dev/null +++ b/pkg/cmd/connector/cluster/list/list.go @@ -0,0 +1,122 @@ +package list + +import ( + "strconv" + + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + "github.com/spf13/cobra" + + "github.com/redhat-developer/app-services-cli/internal/build" +) + +// row is the details of a Kafka instance needed to print to a table +type itemRow struct { + ID string `json:"id" header:"ID"` + Name string `json:"name" header:"Name"` + Owner string `json:"owner" header:"Owner"` + Status string `json:"status" header:"Status"` +} + +type options struct { + outputFormat string + page int + limit int + + f *factory.Factory +} + +// NewListCommand creates a new command to list connector clusters +func NewListCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + page: 0, + limit: 100, + f: f, + } + + cmd := &cobra.Command{ + Use: "list", + Short: f.Localizer.MustLocalize("connector.cluster.list.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cluster.list.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cluster.list.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + + return runList(opts) + }, + } + + flags := flagutil.NewFlagSet(cmd, f.Localizer) + + flags.AddOutput(&opts.outputFormat) + flags.IntVar(&opts.page, "page", int(cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber)), f.Localizer.MustLocalize("connector.common.list.flag.page")) + flags.IntVar(&opts.limit, "limit", 100, f.Localizer.MustLocalize("connector.common.list.flag.limit")) + + return cmd +} + +func runList(opts *options) error { + f := opts.f + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorClustersApi.ListConnectorClusters(f.Context) + a = a.Page(strconv.Itoa(opts.page)) + a = a.Size(strconv.Itoa(opts.limit)) + + response, _, err := a.Execute() + if err != nil { + return err + } + + if response.Size == 0 && opts.outputFormat == "" { + f.Logger.Info(f.Localizer.MustLocalize("connector.common.log.info.noResults")) + return nil + } + + switch opts.outputFormat { + case dump.EmptyFormat: + var rows []itemRow + rows = mapResponseItemsToRows(response.Items) + + dump.Table(f.IOStreams.Out, rows) + f.Logger.Info("") + default: + return dump.Formatted(f.IOStreams.Out, opts.outputFormat, response) + } + return nil +} + +func mapResponseItemsToRows(items []connectormgmtclient.ConnectorCluster) []itemRow { + rows := make([]itemRow, len(items)) + + for i := range items { + k := items[i] + name := k.GetName() + status := k.GetStatus() + + row := itemRow{ + ID: k.GetId(), + Name: name, + Owner: k.GetOwner(), + Status: string(status.GetState()), + } + + rows[i] = row + } + + return rows +} diff --git a/pkg/cmd/connector/connector.go b/pkg/cmd/connector/connector.go new file mode 100644 index 000000000..ed1b73237 --- /dev/null +++ b/pkg/cmd/connector/connector.go @@ -0,0 +1,41 @@ +package connector + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/cluster" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/create" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/delete" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/describe" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/list" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/namespace" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/update" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/profile" + + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +// NewConnectorCommand creates a new command to manage connectors +func NewConnectorsCommand(f *factory.Factory) *cobra.Command { + cmd := &cobra.Command{ + Use: "connector", + Hidden: true, + Annotations: profile.DevPreviewAnnotation(), + Short: f.Localizer.MustLocalize("connector.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.cmd.example"), + Args: cobra.MinimumNArgs(1), + } + + // add sub-commands + cmd.AddCommand( + cluster.NewConnectorClusterCommand(f), + create.NewCreateCommand(f), + delete.NewDeleteCommand(f), + list.NewListCommand(f), + describe.NewDescribeCommand(f), + namespace.NewNameSpaceCommand(f), + update.NewUpdateCommand(f), + ) + + return cmd +} diff --git a/pkg/cmd/connector/connectorcmdutil/flagset.go b/pkg/cmd/connector/connectorcmdutil/flagset.go new file mode 100644 index 000000000..36c85e680 --- /dev/null +++ b/pkg/cmd/connector/connectorcmdutil/flagset.go @@ -0,0 +1,37 @@ +package connectorcmdutil + +import ( + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type FlagSet struct { + cmd *cobra.Command + factory *factory.Factory + *flagutil.FlagSet +} + +// NewFlagSet returns a new flag set with common connector flags +func NewFlagSet(cmd *cobra.Command, f *factory.Factory) *FlagSet { + return &FlagSet{ + cmd: cmd, + factory: f, + FlagSet: flagutil.NewFlagSet(cmd, f.Localizer), + } +} + +// AddConnectorID adds a flag for specifying the connector ID +func (fs *FlagSet) AddConnectorID(ruleType *string) *flagutil.FlagOptions { + flagName := "id" + + fs.StringVar( + ruleType, + flagName, + "", + fs.factory.Localizer.MustLocalize("connector.common.flag.id.description"), + ) + + return flagutil.WithFlagOptions(fs.cmd, flagName) + +} diff --git a/pkg/cmd/connector/connectorcmdutil/validators.go b/pkg/cmd/connector/connectorcmdutil/validators.go new file mode 100644 index 000000000..eef8a1425 --- /dev/null +++ b/pkg/cmd/connector/connectorcmdutil/validators.go @@ -0,0 +1,28 @@ +package connectorcmdutil + +import ( + "regexp" + + "github.com/redhat-developer/app-services-cli/pkg/core/localize" +) + +const ( + legalNamespaceChars = "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" +) + +// Validator is a type for validating connector attributes +type Validator struct { + Localizer localize.Localizer +} + +// ValidateNamespace validates the name of the namespace +func (v *Validator) ValidateNamespace(name string) error { + + matched, _ := regexp.Match(legalNamespaceChars, []byte(name)) + + if matched { + return nil + } + + return v.Localizer.MustLocalizeError("connector.common.validation.namespace.error.invalidChars", localize.NewEntry("Namespace", name)) +} diff --git a/pkg/cmd/connector/create/create.go b/pkg/cmd/connector/create/create.go new file mode 100644 index 000000000..671ddec48 --- /dev/null +++ b/pkg/cmd/connector/create/create.go @@ -0,0 +1,114 @@ +package create + +import ( + "encoding/json" + "io/ioutil" + "os" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/spf13/cobra" +) + +type options struct { + file string + outputFormat string + f *factory.Factory +} + +// NewCreateCommand creates a new command to create a Connector +func NewCreateCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "create", + Short: f.Localizer.MustLocalize("connector.create.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.create.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.create.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runCreate(opts) + }, + } + flags := flagutil.NewFlagSet(cmd, f.Localizer) + flags.StringVar(&opts.file, "file", "", f.Localizer.MustLocalize("connector.file.flag.description")) + flags.AddOutput(&opts.outputFormat) + + return cmd +} + +func runCreate(opts *options) error { + f := opts.f + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + var specifiedFile *os.File + if opts.file == "" { + opts.f.Logger.Info(opts.f.Localizer.MustLocalize("common.message.reading.file")) + file, newErr := util.CreateFileFromStdin() + if newErr != nil { + return newErr + } + specifiedFile = file + } else { + if util.IsURL(opts.file) { + specifiedFile, err = util.GetContentFromFileURL(f.Context, opts.file) + } else { + specifiedFile, err = os.Open(opts.file) + } + if err != nil { + return err + } + } + defer specifiedFile.Close() + + byteValue, err := ioutil.ReadAll(specifiedFile) + if err != nil { + return err + } + var connector connectormgmtclient.ConnectorRequest + err = json.Unmarshal(byteValue, &connector) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorsApi.CreateConnector(f.Context) + a = a.ConnectorRequest(connector) + a = a.Async(true) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.create.info.success")) + + return nil +} diff --git a/pkg/cmd/connector/delete/delete.go b/pkg/cmd/connector/delete/delete.go new file mode 100644 index 000000000..58665a788 --- /dev/null +++ b/pkg/cmd/connector/delete/delete.go @@ -0,0 +1,105 @@ +package delete + +import ( + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + "github.com/spf13/cobra" +) + +type options struct { + id string + outputFormat string + + f *factory.Factory + skipConfirm bool +} + +// NewDeleteCommand creates a new command to delete a connector +func NewDeleteCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "delete", + Short: f.Localizer.MustLocalize("connector.delete.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.delete.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.delete.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runDelete(opts) + }, + } + + flags := connectorcmdutil.NewFlagSet(cmd, f) + flags.AddOutput(&opts.outputFormat) + _ = flags.AddConnectorID(&opts.id).Required() + flags.AddYes(&opts.skipConfirm) + + return cmd +} + +func runDelete(opts *options) error { + f := opts.f + + if !opts.skipConfirm { + confirm, promptErr := promptConfirmDelete(opts) + if promptErr != nil { + return promptErr + } + if !confirm { + opts.f.Logger.Debug("User has chosen to not delete connector cluster") + return nil + } + } + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorsApi.DeleteConnector(f.Context, opts.id) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.delete.info.success")) + + return nil +} + +func promptConfirmDelete(opts *options) (bool, error) { + promptConfirm := survey.Confirm{ + Message: opts.f.Localizer.MustLocalize("connector.delete.confirmDialog.message", localize.NewEntry("ID", opts.id)), + } + + var confirmDelete bool + if err := survey.AskOne(&promptConfirm, &confirmDelete); err != nil { + return false, err + } + return confirmDelete, nil +} diff --git a/pkg/cmd/connector/describe/describe.go b/pkg/cmd/connector/describe/describe.go new file mode 100644 index 000000000..cb40e81a7 --- /dev/null +++ b/pkg/cmd/connector/describe/describe.go @@ -0,0 +1,78 @@ +package describe + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + "github.com/spf13/cobra" +) + +type options struct { + id string + outputFormat string + + f *factory.Factory +} + +// NewDescribeCommand creates a new command to view a connector +func NewDescribeCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "describe", + Short: f.Localizer.MustLocalize("connector.describe.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.describe.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.describe.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runDescribe(opts) + }, + } + flags := connectorcmdutil.NewFlagSet(cmd, f) + _ = flags.AddConnectorID(&opts.id).Required() + flags.AddOutput(&opts.outputFormat) + + return cmd +} + +func runDescribe(opts *options) error { + f := opts.f + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorsApi.GetConnector(f.Context, opts.id) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.describe.info.success")) + + return nil +} diff --git a/pkg/cmd/connector/list/list.go b/pkg/cmd/connector/list/list.go new file mode 100644 index 000000000..0d8d403a4 --- /dev/null +++ b/pkg/cmd/connector/list/list.go @@ -0,0 +1,121 @@ +package list + +import ( + "strconv" + + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + "github.com/spf13/cobra" + + "github.com/redhat-developer/app-services-cli/internal/build" +) + +// row is the details of a Kafka instance needed to print to a table +type itemRow struct { + ID string `json:"id" header:"ID"` + Name string `json:"name" header:"Name"` + Owner string `json:"owner" header:"Owner"` + Status string `json:"status" header:"Status"` +} + +type options struct { + outputFormat string + page int + limit int + + f *factory.Factory +} + +// NewListCommand creates a new command to list connectors +func NewListCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + page: 0, + limit: 100, + f: f, + } + + cmd := &cobra.Command{ + Use: "list", + Short: f.Localizer.MustLocalize("connector.list.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.list.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.list.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + + return runList(opts) + }, + } + + flags := flagutil.NewFlagSet(cmd, f.Localizer) + + flags.AddOutput(&opts.outputFormat) + flags.IntVar(&opts.page, "page", int(cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber)), f.Localizer.MustLocalize("connector.common.list.flag.page")) + flags.IntVar(&opts.limit, "limit", int(cmdutil.ConvertPageValueToInt32(build.DefaultPageSize)), f.Localizer.MustLocalize("connector.common.list.flag.limit")) + + return cmd +} + +func runList(opts *options) error { + f := opts.f + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorsApi.ListConnectors(f.Context) + a = a.Page(strconv.Itoa(opts.page)) + a = a.Size(strconv.Itoa(opts.limit)) + + response, _, err := a.Execute() + if err != nil { + return err + } + + if response.Size == 0 && opts.outputFormat == "" { + f.Logger.Info(f.Localizer.MustLocalize("connector.common.log.info.noResults")) + return nil + } + + switch opts.outputFormat { + case dump.EmptyFormat: + var rows []itemRow + rows = mapResponseItemsToRows(response.Items) + + dump.Table(f.IOStreams.Out, rows) + f.Logger.Info("") + default: + return dump.Formatted(f.IOStreams.Out, opts.outputFormat, response) + } + return nil +} + +func mapResponseItemsToRows(items []connectormgmtclient.Connector) []itemRow { + rows := make([]itemRow, len(items)) + + for i := range items { + k := items[i] + name := k.GetName() + + row := itemRow{ + ID: k.GetId(), + Name: name, + Owner: k.GetOwner(), + Status: string(*k.Status.State), + } + + rows[i] = row + } + + return rows +} diff --git a/pkg/cmd/connector/namespace/create/create.go b/pkg/cmd/connector/namespace/create/create.go new file mode 100644 index 000000000..fafa34b30 --- /dev/null +++ b/pkg/cmd/connector/namespace/create/create.go @@ -0,0 +1,97 @@ +package create + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" + + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" +) + +type options struct { + f *factory.Factory + + name string + eval bool + outputFormat string +} + +// NewCreateCommand a new command to create a new namespace +func NewCreateCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "create", + Short: f.Localizer.MustLocalize("connector.namespace.create.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.namespace.create.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.namespace.create.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + validator := connectorcmdutil.Validator{ + Localizer: f.Localizer, + } + + if err := validator.ValidateNamespace(opts.name); err != nil { + return err + } + + return runCreate(opts) + }, + } + + flags := flagutil.NewFlagSet(cmd, f.Localizer) + flags.StringVar(&opts.name, "name", "", f.Localizer.MustLocalize("connector.namespace.create.flag.name.description")) + flags.BoolVar(&opts.eval, "eval", false, f.Localizer.MustLocalize("connector.namespace.create.flag.eval.description")) + flags.AddOutput(&opts.outputFormat) + + return cmd +} + +func runCreate(opts *options) error { + + f := opts.f + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorNamespacesApi.CreateEvaluationNamespace(f.Context) + + connectorNameSpaceEvalReq := connectormgmtclient.ConnectorNamespaceEvalRequest{ + Name: &opts.name, + } + + var connector connectormgmtclient.ConnectorNamespace + var newErr error + + if opts.eval { + a = api.ConnectorsMgmt().ConnectorNamespacesApi.CreateEvaluationNamespace(f.Context) + a = a.ConnectorNamespaceEvalRequest(connectorNameSpaceEvalReq) + connector, _, newErr = a.Execute() + } else { + a = a.ConnectorNamespaceEvalRequest(connectorNameSpaceEvalReq) + connector, _, newErr = a.Execute() + } + + if newErr != nil { + return newErr + } + + if newErr = dump.Formatted(f.IOStreams.Out, opts.outputFormat, connector); newErr != nil { + return newErr + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.namespace.create.info.success")) + + return nil + +} diff --git a/pkg/cmd/connector/namespace/delete/delete.go b/pkg/cmd/connector/namespace/delete/delete.go new file mode 100644 index 000000000..39a727d2e --- /dev/null +++ b/pkg/cmd/connector/namespace/delete/delete.go @@ -0,0 +1,93 @@ +package delete + +import ( + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + f *factory.Factory + + id string + skipConfirm bool +} + +// NewDeleteCommand deletes a specified namespace +func NewDeleteCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "delete", + Short: f.Localizer.MustLocalize("connector.namespace.delete.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.namespace.delete.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.namespace.delete.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return runDelete(opts) + }, + } + + flags := connectorcmdutil.NewFlagSet(cmd, f) + _ = flags.AddConnectorID(&opts.id).Required() + + return cmd + +} + +func runDelete(opts *options) error { + + f := opts.f + + if !opts.skipConfirm { + confirm, promptErr := promptConfirmDelete(opts) + if promptErr != nil { + return promptErr + } + if !confirm { + opts.f.Logger.Debug("User has chosen to not delete connector cluster") + return nil + } + } + + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorNamespacesApi.DeleteConnectorNamespace(f.Context, opts.id) + _, httpRes, err := a.Execute() + + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.namespace.delete.info.success")) + + return nil + +} + +func promptConfirmDelete(opts *options) (bool, error) { + promptConfirm := survey.Confirm{ + Message: opts.f.Localizer.MustLocalize("connector.namespace.delete.confirmDialog.message", localize.NewEntry("ID", opts.id)), + } + + var confirmDelete bool + if err := survey.AskOne(&promptConfirm, &confirmDelete); err != nil { + return false, err + } + return confirmDelete, nil +} diff --git a/pkg/cmd/connector/namespace/list/list.go b/pkg/cmd/connector/namespace/list/list.go new file mode 100644 index 000000000..4dd4f1f23 --- /dev/null +++ b/pkg/cmd/connector/namespace/list/list.go @@ -0,0 +1,120 @@ +package list + +import ( + "strconv" + + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + "github.com/spf13/cobra" + + "github.com/redhat-developer/app-services-cli/internal/build" +) + +// row is the details of a Kafka instance needed to print to a table +type itemRow struct { + ID string `json:"id" header:"ID"` + Name string `json:"name" header:"Name"` + Owner string `json:"owner" header:"Owner"` + Cluster string `json:"clusterId" header:"Cluster ID"` +} + +type options struct { + outputFormat string + page int + limit int + + f *factory.Factory +} + +func NewListCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + page: 0, + limit: 100, + f: f, + } + + cmd := &cobra.Command{ + Use: "list", + Short: f.Localizer.MustLocalize("connector.namespace.list.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.namespace.list.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.namespace.list.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + + return runList(opts) + }, + } + + flags := flagutil.NewFlagSet(cmd, f.Localizer) + + flags.AddOutput(&opts.outputFormat) + flags.IntVar(&opts.page, "page", int(cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber)), f.Localizer.MustLocalize("connector.common.list.flag.page")) + flags.IntVar(&opts.limit, "limit", 100, f.Localizer.MustLocalize("connector.common.list.flag.limit")) + + return cmd +} + +func runList(opts *options) error { + f := opts.f + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorNamespacesApi.ListConnectorNamespaces(f.Context) + a = a.Page(strconv.Itoa(opts.page)) + a = a.Size(strconv.Itoa(opts.limit)) + + response, _, err := a.Execute() + if err != nil { + return err + } + + if response.Size == 0 && opts.outputFormat == "" { + f.Logger.Info(f.Localizer.MustLocalize("connector.common.log.info.noResults")) + return nil + } + + switch opts.outputFormat { + case dump.EmptyFormat: + var rows []itemRow + rows = mapResponseItemsToRows(response.Items) + + dump.Table(f.IOStreams.Out, rows) + f.Logger.Info("") + default: + return dump.Formatted(f.IOStreams.Out, opts.outputFormat, response) + } + return nil +} + +func mapResponseItemsToRows(items []connectormgmtclient.ConnectorNamespace) []itemRow { + rows := make([]itemRow, len(items)) + + for i := range items { + k := items[i] + name := k.GetName() + + row := itemRow{ + ID: k.GetId(), + Name: name, + Owner: k.GetOwner(), + Cluster: k.GetClusterId(), + } + + rows[i] = row + } + + return rows +} diff --git a/pkg/cmd/connector/namespace/namespace.go b/pkg/cmd/connector/namespace/namespace.go new file mode 100644 index 000000000..d1a526dda --- /dev/null +++ b/pkg/cmd/connector/namespace/namespace.go @@ -0,0 +1,29 @@ +package namespace + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/namespace/create" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/namespace/delete" + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/namespace/list" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +// NewNamespaceCommand creates a new command to manage connector namespaces +func NewNameSpaceCommand(f *factory.Factory) *cobra.Command { + cmd := &cobra.Command{ + Use: "namespace", + Short: f.Localizer.MustLocalize("connector.namespace.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.namespace.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.namespace.cmd.example"), + Args: cobra.MinimumNArgs(1), + } + + // add sub-commands + cmd.AddCommand( + list.NewListCommand(f), + create.NewCreateCommand(f), + delete.NewDeleteCommand(f), + ) + + return cmd +} diff --git a/pkg/cmd/connector/update/update.go b/pkg/cmd/connector/update/update.go new file mode 100644 index 000000000..1f03ebc76 --- /dev/null +++ b/pkg/cmd/connector/update/update.go @@ -0,0 +1,117 @@ +package update + +import ( + "encoding/json" + "io/ioutil" + "os" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector/connectorcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + file string + + outputFormat string + f *factory.Factory + id string +} + +// NewUpdateCommand creates a new command to update a connector +func NewUpdateCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "update", + Short: f.Localizer.MustLocalize("connector.update.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("connector.update.cmd.longDescription"), + Example: f.Localizer.MustLocalize("connector.update.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + validOutputFormats := flagutil.ValidOutputFormats + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, validOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, validOutputFormats...) + } + + return runUpdateCommand(opts) + }, + } + + flags := connectorcmdutil.NewFlagSet(cmd, f) + flags.StringVar(&opts.file, "file", "", f.Localizer.MustLocalize("connector.file.flag.description")) + flags.AddConnectorID(&opts.id) + flags.AddOutput(&opts.outputFormat) + + return cmd + +} + +func runUpdateCommand(opts *options) error { + f := opts.f + + var conn connection.Connection + conn, err := f.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + var specifiedFile *os.File + if opts.file == "" { + file, err1 := util.CreateFileFromStdin() + if err1 != nil { + return err + } + specifiedFile = file + } else { + if util.IsURL(opts.file) { + specifiedFile, err = util.GetContentFromFileURL(f.Context, opts.file) + } else { + specifiedFile, err = os.Open(opts.file) + } + if err != nil { + return err + } + } + defer specifiedFile.Close() + + byteValue, err := ioutil.ReadAll(specifiedFile) + if err != nil { + return err + } + var connector map[string]interface{} + err = json.Unmarshal(byteValue, &connector) + if err != nil { + return err + } + + api := conn.API() + + a := api.ConnectorsMgmt().ConnectorsApi.PatchConnector(f.Context, opts.id) + a = a.Body(connector) + + response, httpRes, err := a.Execute() + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return err + } + + if err = dump.Formatted(f.IOStreams.Out, opts.outputFormat, response); err != nil { + return err + } + + f.Logger.Info(f.Localizer.MustLocalize("connector.update.info.success")) + + return nil +} diff --git a/pkg/cmd/context/context.go b/pkg/cmd/context/context.go new file mode 100644 index 000000000..9d993722c --- /dev/null +++ b/pkg/cmd/context/context.go @@ -0,0 +1,54 @@ +package context + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/create" + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/delete" + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/list" + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/use" + kafkaUse "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/use" + registryUse "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/use" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/status" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +// NewContextCmd creates a new command to manage service contexts +func NewContextCmd(f *factory.Factory) *cobra.Command { + + cmd := &cobra.Command{ + Use: "context", + Short: f.Localizer.MustLocalize("context.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("context.cmd.longDescription"), + Example: f.Localizer.MustLocalize("context.cmd.example"), + Args: cobra.NoArgs, + } + + // The implementation of `rhoas kafka use` command has been aliased here as `rhoas context use-kafka` + kafkaUseCmd := kafkaUse.NewUseCommand(f) + kafkaUseCmd.Use = "use-kafka" + kafkaUseCmd.Example = f.Localizer.MustLocalize("context.useKafka.cmd.example") + + // `rhoas status` cmd has been re-used as `rhoas context status` + statusCmd := status.NewStatusCommand(f) + statusCmd.Long = f.Localizer.MustLocalize("context.status.cmd.longDescription") + statusCmd.Example = f.Localizer.MustLocalize("context.status.cmd.example") + + // The implementation of `rhoas service-registry use` command has been aliased here as `rhoas context use-service-registry` + registryUseCmd := registryUse.NewUseCommand(f) + registryUseCmd.Use = "use-service-registry" + registryUseCmd.Example = f.Localizer.MustLocalize("context.useRegistry.cmd.example") + + cmd.AddCommand( + use.NewUseCommand(f), + list.NewListCommand(f), + create.NewCreateCommand(f), + delete.NewDeleteCommand(f), + + // reused sub-commands + kafkaUseCmd, + registryUseCmd, + statusCmd, + ) + return cmd +} diff --git a/pkg/cmd/context/contextcmdutil/flagset.go b/pkg/cmd/context/contextcmdutil/flagset.go new file mode 100644 index 000000000..03dd7d4a1 --- /dev/null +++ b/pkg/cmd/context/contextcmdutil/flagset.go @@ -0,0 +1,50 @@ +package contextcmdutil + +import ( + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type FlagSet struct { + cmd *cobra.Command + factory *factory.Factory + *flagutil.FlagSet +} + +// NewFlagSet returns a new flag set with common context flags +func NewFlagSet(cmd *cobra.Command, f *factory.Factory) *FlagSet { + return &FlagSet{ + cmd: cmd, + factory: f, + FlagSet: flagutil.NewFlagSet(cmd, f.Localizer), + } +} + +// AddContextName adds a flag for setting the name of the context +func (fs *FlagSet) AddContextName(name *string) *flagutil.FlagOptions { + + svcContext, _ := fs.factory.ServiceContext.Load() + + svcContextsMap := svcContext.Contexts + flagName := "name" + + fs.StringVar( + name, + flagName, + "", + fs.factory.Localizer.MustLocalize("context.common.flag.name"), + ) + + contextNames := make([]string, 0, len(svcContextsMap)) + for k := range svcContextsMap { + contextNames = append(contextNames, k) + } + + _ = fs.cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { + return contextNames, cobra.ShellCompDirectiveNoSpace + }) + + return flagutil.WithFlagOptions(fs.cmd, flagName) + +} diff --git a/pkg/cmd/context/contextcmdutil/validator.go b/pkg/cmd/context/contextcmdutil/validator.go new file mode 100644 index 000000000..c4e1e240a --- /dev/null +++ b/pkg/cmd/context/contextcmdutil/validator.go @@ -0,0 +1,52 @@ +package contextcmdutil + +import ( + "regexp" + + "github.com/redhat-developer/app-services-cli/pkg/core/errors" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" +) + +// Validator is a type for validating service context inputs +type Validator struct { + Localizer localize.Localizer + SvcContext *servicecontext.Context +} + +const ( + legalNameChars = "^[a-z]([-a-z0-9]*[a-z0-9])?$" +) + +// ValidateName validates the name of the context +func (v *Validator) ValidateName(val interface{}) error { + + name, ok := val.(string) + if !ok { + return errors.NewCastError(val, "string") + } + + if len(name) < 1 { + return v.Localizer.MustLocalizeError("context.common.validation.name.error.required") + } + + matched, _ := regexp.Match(legalNameChars, []byte(name)) + + if matched { + return nil + } + + return v.Localizer.MustLocalizeError("context.common.validation.name.error.invalidChars", localize.NewEntry("Name", name)) +} + +// ValidateNameIsAvailable validates if the name provided is a unique context name +func (v *Validator) ValidateNameIsAvailable(name string) error { + + context, _ := contextutil.GetContext(v.SvcContext, v.Localizer, name) + if context != nil { + return v.Localizer.MustLocalizeError("context.create.log.alreadyExists", localize.NewEntry("Name", name)) + } + + return nil +} diff --git a/pkg/cmd/context/create/create.go b/pkg/cmd/context/create/create.go new file mode 100644 index 000000000..ed56d41e4 --- /dev/null +++ b/pkg/cmd/context/create/create.go @@ -0,0 +1,110 @@ +package create + +import ( + "context" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/contextcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + + name string +} + +// NewCreateCommand creates a new command to create contexts +func NewCreateCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + ServiceContext: f.ServiceContext, + } + + cmd := &cobra.Command{ + Use: "create", + Short: f.Localizer.MustLocalize("context.create.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("context.create.cmd.longDescription"), + Example: f.Localizer.MustLocalize("context.create.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + return runCreate(opts) + }, + } + + flags := contextcmdutil.NewFlagSet(cmd, f) + + flags.StringVar( + &opts.name, + "name", + "", + opts.localizer.MustLocalize("context.common.flag.name"), + ) + + return cmd + +} + +func runCreate(opts *options) error { + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + profileValidator := &contextcmdutil.Validator{ + Localizer: opts.localizer, + SvcContext: svcContext, + } + + svcContextsMap := svcContext.Contexts + + if svcContextsMap == nil { + svcContextsMap = make(map[string]servicecontext.ServiceConfig) + } + + err = profileValidator.ValidateName(opts.name) + if err != nil { + return err + } + + err = profileValidator.ValidateNameIsAvailable(opts.name) + if err != nil { + return err + } + + context, _ := contextutil.GetContext(svcContext, opts.localizer, opts.name) + if context != nil { + return opts.localizer.MustLocalizeError("context.create.log.alreadyExists", localize.NewEntry("Name", opts.name)) + } + + svcContextsMap[opts.name] = servicecontext.ServiceConfig{} + svcContext.CurrentContext = opts.name + + svcContext.Contexts = svcContextsMap + + err = opts.ServiceContext.Save(svcContext) + if err != nil { + return err + } + + opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("context.create.log.successMessage", localize.NewEntry("Name", opts.name))) + + return nil +} diff --git a/pkg/cmd/context/delete/delete.go b/pkg/cmd/context/delete/delete.go new file mode 100644 index 000000000..8284eff25 --- /dev/null +++ b/pkg/cmd/context/delete/delete.go @@ -0,0 +1,94 @@ +package delete + +import ( + "context" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/contextcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + + name string +} + +// NewDeleteCommand command for deleting service contexts +func NewDeleteCommand(f *factory.Factory) *cobra.Command { + opts := &options{ + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, + } + + cmd := &cobra.Command{ + Use: "delete", + Short: f.Localizer.MustLocalize("context.delete.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("context.delete.cmd.longDescription"), + Example: f.Localizer.MustLocalize("context.delete.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return runDelete(opts) + }, + } + + flags := contextcmdutil.NewFlagSet(cmd, f) + + flags.AddContextName(&opts.name) + + return cmd +} + +func runDelete(opts *options) error { + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx := svcContext.CurrentContext + + if opts.name == "" || opts.name == currCtx { + + if currCtx == "" { + return opts.localizer.MustLocalizeError("context.common.error.notSet") + } + + opts.name = currCtx + + svcContext.CurrentContext = "" + + opts.Logger.Info(opts.localizer.MustLocalize("context.delete.log.warning.currentUnset")) + } + + if _, err = contextutil.GetContext(svcContext, opts.localizer, opts.name); err != nil { + return err + } + + delete(svcContext.Contexts, opts.name) + + err = opts.ServiceContext.Save(svcContext) + if err != nil { + return err + } + + opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("context.delete.log.successMessage")) + + return nil + +} diff --git a/pkg/cmd/context/list/list.go b/pkg/cmd/context/list/list.go new file mode 100644 index 000000000..a6b30237a --- /dev/null +++ b/pkg/cmd/context/list/list.go @@ -0,0 +1,89 @@ +package list + +import ( + "context" + "fmt" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/contextcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + + outputFormat string +} + +// NewListCommand creates a new command to list available contexts +func NewListCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + ServiceContext: f.ServiceContext, + } + + cmd := &cobra.Command{ + Use: "list", + Short: f.Localizer.MustLocalize("context.list.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("context.list.cmd.longDescription"), + Example: f.Localizer.MustLocalize("context.list.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return runList(opts) + }, + } + + flags := contextcmdutil.NewFlagSet(cmd, f) + + flags.AddOutput(&opts.outputFormat) + + return cmd +} + +func runList(opts *options) error { + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + svcContextsMap := svcContext.Contexts + + if svcContextsMap == nil { + opts.Logger.Info(opts.localizer.MustLocalize("context.list.log.info.noContexts")) + return nil + } + + if opts.outputFormat == dump.EmptyFormat { + currentCtx := svcContext.CurrentContext + var profileList string + + for name := range svcContextsMap { + if currentCtx != "" && name == currentCtx { + profileList += fmt.Sprintln(name, icon.SuccessPrefix()) + } else { + profileList += fmt.Sprintln(name) + } + } + opts.Logger.Info(profileList) + return nil + } + + return dump.Formatted(opts.IO.Out, opts.outputFormat, svcContextsMap) + +} diff --git a/pkg/cmd/context/use/use.go b/pkg/cmd/context/use/use.go new file mode 100644 index 000000000..d03fec232 --- /dev/null +++ b/pkg/cmd/context/use/use.go @@ -0,0 +1,128 @@ +package use + +import ( + "context" + + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/contextcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext + + name string +} + +// NewUseCommand creates a new command to set the current context +func NewUseCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + ServiceContext: f.ServiceContext, + } + + cmd := &cobra.Command{ + Use: "use", + Short: f.Localizer.MustLocalize("context.use.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("context.use.cmd.longDescription"), + Example: f.Localizer.MustLocalize("context.use.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + if !opts.IO.CanPrompt() && opts.name == "" { + return flagutil.RequiredWhenNonInteractiveError("name") + } + + return runUse(opts) + }, + } + + flags := contextcmdutil.NewFlagSet(cmd, f) + + flags.AddContextName(&opts.name) + + return cmd +} + +func runUse(opts *options) error { + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + if opts.name == "" { + opts.name, err = runInteractivePrompt(opts, svcContext) + if err != nil { + return err + } + } + + _, err = contextutil.GetContext(svcContext, opts.localizer, opts.name) + if err != nil { + return err + } + + svcContext.CurrentContext = opts.name + + err = opts.ServiceContext.Save(svcContext) + if err != nil { + return err + } + + opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("context.use.successMessage", localize.NewEntry("Name", opts.name))) + + return nil +} + +func runInteractivePrompt(opts *options, context *servicecontext.Context) (string, error) { + + svcContextsMap := context.Contexts + + if svcContextsMap == nil { + svcContextsMap = make(map[string]servicecontext.ServiceConfig) + } + + profileNames := make([]string, 0, len(svcContextsMap)) + + for name := range svcContextsMap { + profileNames = append(profileNames, name) + } + + if len(profileNames) == 0 { + opts.Logger.Info(opts.localizer.MustLocalize("context.list.log.info.noContexts")) + return "", nil + } + + prompt := &survey.Select{ + Message: opts.localizer.MustLocalize("context.common.flag.name"), + Options: profileNames, + PageSize: 10, + } + + var selectedServiceContext string + err := survey.AskOne(prompt, &selectedServiceContext) + if err != nil { + return "", err + } + + return selectedServiceContext, nil + +} diff --git a/pkg/cmd/generate/build-configs.go b/pkg/cmd/generate/build-configs.go new file mode 100644 index 000000000..fd58f265e --- /dev/null +++ b/pkg/cmd/generate/build-configs.go @@ -0,0 +1,117 @@ +package generate + +import ( + "fmt" + "time" + + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + + kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" +) + +type configValues struct { + KafkaHost string + RegistryURL string + ClientID string + ClientSecret string + TokenURL string +} + +func createServiceAccount(opts *options, shortDescription string) (*kafkamgmtclient.ServiceAccount, error) { + + conn, err := opts.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return nil, err + } + + serviceAccountPayload := kafkamgmtclient.ServiceAccountRequest{Name: shortDescription} + + serviceacct, httpRes, err := conn.API(). + ServiceAccountMgmt(). + CreateServiceAccount(opts.Context). + ServiceAccountRequest(serviceAccountPayload). + Execute() + + if httpRes != nil { + defer httpRes.Body.Close() + } + + if err != nil { + return nil, err + } + + return &serviceacct, nil +} + +// BuildConfiguration builds the configs for the service context +func BuildConfiguration(svcConfig *servicecontext.ServiceConfig, opts *options) error { + + factory := &factory.Factory{ + IOStreams: opts.IO, + Logger: opts.Logger, + Context: opts.Context, + Localizer: opts.localizer, + Connection: opts.Connection, + ServiceContext: opts.ServiceContext, + } + + cfg, err := opts.Config.Load() + if err != nil { + return err + } + + configurations := &configValues{} + + var serviceAvailable bool + + if svcConfig.KafkaID != "" { + kafkaInstance, newErr := contextutil.GetCurrentKafkaInstance(factory) + if newErr != nil { + return newErr + } + + serviceAvailable = true + configurations.KafkaHost = kafkaInstance.GetBootstrapServerHost() + } + + if svcConfig.ServiceRegistryID != "" { + registryInstance, newErr := contextutil.GetCurrentRegistryInstance(factory) + if newErr != nil { + return newErr + } + + serviceAvailable = true + configurations.RegistryURL = registryInstance.GetRegistryUrl() + } + + if !serviceAvailable { + return opts.localizer.MustLocalizeError("generate.log.info.noSevices") + } + + serviceAccount, err := createServiceAccount(opts, fmt.Sprintf("%s-%v", opts.name, time.Now().Unix())) + if err != nil { + return err + } + + opts.Logger.Info( + icon.SuccessPrefix(), + opts.localizer.MustLocalize("serviceAccount.create.log.info.createdSuccessfully", localize.NewEntry("ID", serviceAccount.GetId())), + ) + + configurations.ClientID = serviceAccount.GetClientId() + configurations.ClientSecret = serviceAccount.GetClientSecret() + configurations.TokenURL = cfg.MasAuthURL + "/protocol/openid-connect/token" + + if err = WriteConfig(opts.configType, configurations); err != nil { + return err + } + + opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("generate.log.info.credentialsSaved")) + + return nil +} diff --git a/pkg/cmd/generate/configurations.go b/pkg/cmd/generate/configurations.go new file mode 100644 index 000000000..c0fcd45cf --- /dev/null +++ b/pkg/cmd/generate/configurations.go @@ -0,0 +1,76 @@ +package generate + +import ( + "bytes" + "html/template" + "io/ioutil" + "os" + "path/filepath" +) + +// configuration types for generate-config command +const ( + envFormat = "env" + jsonFormat = "json" + propertiesFormat = "properties" +) + +var configurationTypes = []string{envFormat, jsonFormat, propertiesFormat} + +var ( + envConfig = template.Must(template.New(envFormat).Parse(templateEnv)) + jsonConfig = template.Must(template.New(jsonFormat).Parse(templateJSON)) + propertiesConfig = template.Must(template.New(propertiesFormat).Parse(templateProperties)) +) + +// WriteConfig saves the configurations to a file +// in the specified output format +func WriteConfig(configType string, config *configValues) error { + + var fileBody bytes.Buffer + fileTemplate := getFileFormat(configType) + err := fileTemplate.Execute(&fileBody, config) + if err != nil { + return err + } + + fileData := []byte(fileBody.String()) + filePath := getDefaultPath(configType) + + return ioutil.WriteFile(filePath, fileData, 0o600) +} + +// getDefaultPath returns the default absolute path for the configuration file +func getDefaultPath(configType string) (filePath string) { + switch configType { + case envFormat: + filePath = "rhoas.env" + case propertiesFormat: + filePath = "rhoas.properties" + case jsonFormat: + filePath = "rhoas.json" + } + + pwd, err := os.Getwd() + if err != nil { + pwd = "./" + } + + filePath = filepath.Join(pwd, filePath) + + return filePath +} + +func getFileFormat(configType string) (template *template.Template) { + + switch configType { + case envFormat: + template = envConfig + case propertiesFormat: + template = propertiesConfig + case jsonFormat: + template = jsonConfig + } + + return template +} diff --git a/pkg/cmd/generate/generate-config.go b/pkg/cmd/generate/generate-config.go new file mode 100644 index 000000000..9250c5f1f --- /dev/null +++ b/pkg/cmd/generate/generate-config.go @@ -0,0 +1,98 @@ +package generate + +import ( + "context" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/context/contextcmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/config" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + Config config.IConfig + ServiceContext servicecontext.IContext + + name string + configType string +} + +// NewGenerateCommand creates configuration files for service context +func NewGenerateCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + Connection: f.Connection, + Config: f.Config, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + ServiceContext: f.ServiceContext, + } + + cmd := &cobra.Command{ + Use: "generate-config", + Short: f.Localizer.MustLocalize("generate.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("generate.cmd.longDescription"), + Example: f.Localizer.MustLocalize("generate.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + + // check that a valid type is provided + validType := flagutil.IsValidInput(opts.configType, configurationTypes...) + if !validType { + return flagutil.InvalidValueError("type", opts.configType, configurationTypes...) + } + + return runGenerate(opts) + }, + } + + flags := contextcmdutil.NewFlagSet(cmd, f) + flags.AddContextName(&opts.name) + flags.StringVar(&opts.configType, "type", "", opts.localizer.MustLocalize("generate.flag.type")) + _ = cmd.MarkFlagRequired("type") + + flagutil.EnableStaticFlagCompletion(cmd, "type", configurationTypes) + + return cmd +} + +func runGenerate(opts *options) error { + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + var svcConfig *servicecontext.ServiceConfig + + if opts.name == "" { + svcConfig, err = contextutil.GetCurrentContext(svcContext, opts.localizer) + if err != nil { + return err + } + opts.name = svcContext.CurrentContext + } else { + svcConfig, err = contextutil.GetContext(svcContext, opts.localizer, opts.name) + if err != nil { + return err + } + } + + if err = BuildConfiguration(svcConfig, opts); err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/generate/templates.go b/pkg/cmd/generate/templates.go new file mode 100644 index 000000000..5ac6b40d8 --- /dev/null +++ b/pkg/cmd/generate/templates.go @@ -0,0 +1,35 @@ +package generate + +import ( + "github.com/MakeNowJust/heredoc" +) + +var ( + templateEnv = heredoc.Doc(` + ## Generated by rhoas generate-config + {{if .KafkaHost}}KAFKA_HOST={{.KafkaHost}} + {{end}}{{if .RegistryURL}}SERVICE_REGISTRY_URL={{.RegistryURL}} + {{end}}RHOAS_CLIENT_ID={{.ClientID}} + RHOAS_CLIENT_SECRET={{.ClientSecret}} + RHOAS_OAUTH_TOKEN_URL={{.TokenURL}} +`) + + templateJSON = heredoc.Doc(` + { + {{if .KafkaHost}}"kafkaHost":"{{.KafkaHost}}", + {{end}}{{if .RegistryURL}}"serviceRegistryUrl":"{{.RegistryURL}}", + {{end}}"rhoasClientID":"{{.ClientID}}", + "rhoasClientSecret":"{{.ClientSecret}}", + "rhoasOauthTokenUrl":"{{.TokenURL}}" + } + `) + + templateProperties = heredoc.Doc(` + ## Generated by rhoas generate-config + {{if .KafkaHost}}kafkaHost={{.KafkaHost}} + {{end}}{{if .RegistryURL}}serviceRegistryUrl={{.RegistryURL}} + {{end}}rhoasClientID={{.ClientID}} + rhoasClientSecret={{.ClientSecret}} + rhoasOauthTokenUrl={{.TokenURL}} + `) +) diff --git a/pkg/cmd/kafka/acl/aclcmdutil/util.go b/pkg/cmd/kafka/acl/aclcmdutil/util.go index 3114f71d5..60ade6f59 100644 --- a/pkg/cmd/kafka/acl/aclcmdutil/util.go +++ b/pkg/cmd/kafka/acl/aclcmdutil/util.go @@ -6,11 +6,11 @@ import ( "fmt" "net/http" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/spf13/cobra" @@ -20,12 +20,12 @@ import ( // CrudOptions is the interface used for options of create and delete command type CrudOptions struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - Localizer localize.Localizer - Context context.Context + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + Localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext Cluster bool PatternType string diff --git a/pkg/cmd/kafka/acl/admin/admin.go b/pkg/cmd/kafka/acl/admin/admin.go index 7a2addad7..4f57c8f80 100644 --- a/pkg/cmd/kafka/acl/admin/admin.go +++ b/pkg/cmd/kafka/acl/admin/admin.go @@ -7,13 +7,14 @@ import ( flagset "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/flagutil" "github.com/AlecAivazis/survey/v2" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -27,12 +28,12 @@ var ( ) type options struct { - config config.IConfig - connection factory.ConnectionFunc - logger logging.Logger - io *iostreams.IOStreams - localizer localize.Localizer - context context.Context + connection factory.ConnectionFunc + logger logging.Logger + io *iostreams.IOStreams + localizer localize.Localizer + context context.Context + serviceContext servicecontext.IContext kafkaID string principal string @@ -43,12 +44,12 @@ type options struct { func NewAdminACLCommand(f *factory.Factory) *cobra.Command { opts := &options{ - config: f.Config, - connection: f.Connection, - logger: f.Logger, - io: f.IOStreams, - localizer: f.Localizer, - context: f.Context, + connection: f.Connection, + logger: f.Logger, + io: f.IOStreams, + localizer: f.Localizer, + context: f.Context, + serviceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -60,18 +61,13 @@ func NewAdminACLCommand(f *factory.Factory) *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { if opts.kafkaID == "" { - cfg, err := opts.config.Load() + + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - - if !ok { - return opts.localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected") - } - - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() } // check if principal is provided diff --git a/pkg/cmd/kafka/acl/create/create.go b/pkg/cmd/kafka/acl/create/create.go index 73b7775b7..fceb7e6aa 100644 --- a/pkg/cmd/kafka/acl/create/create.go +++ b/pkg/cmd/kafka/acl/create/create.go @@ -10,6 +10,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/spinner" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" "github.com/spf13/cobra" @@ -34,12 +35,12 @@ type requestParams struct { // NewCreateCommand creates a new command to add Kafka ACLs func NewCreateCommand(f *factory.Factory) *cobra.Command { opts := &aclcmdutil.CrudOptions{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - Localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + Localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -77,6 +78,16 @@ func NewCreateCommand(f *factory.Factory) *cobra.Command { return aclcmdutil.BuildInstructions(errorCollection) } + if opts.InstanceID == "" { + + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } + + opts.InstanceID = kafkaInstance.GetId() + } + return runAdd(opts.InstanceID, opts) }, } @@ -230,20 +241,5 @@ func validateAndSetOpts(opts *aclcmdutil.CrudOptions) error { opts.Principal = serviceAccount } - if opts.InstanceID == "" { - cfg, err := opts.Config.Load() - if err != nil { - return err - } - - instanceID, ok := cfg.GetKafkaIdOk() - - if !ok { - return opts.Localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected") - } - - opts.InstanceID = instanceID - } - return nil } diff --git a/pkg/cmd/kafka/acl/delete/delete.go b/pkg/cmd/kafka/acl/delete/delete.go index ce4758861..d823a1002 100644 --- a/pkg/cmd/kafka/acl/delete/delete.go +++ b/pkg/cmd/kafka/acl/delete/delete.go @@ -11,6 +11,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/spinner" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" "github.com/spf13/cobra" @@ -36,7 +37,6 @@ type requestParams struct { // NewDeleteCommand creates a new command to delete Kafka ACLs func NewDeleteCommand(f *factory.Factory) *cobra.Command { opts := &aclcmdutil.CrudOptions{ - Config: f.Config, Connection: f.Connection, Logger: f.Logger, IO: f.IOStreams, @@ -71,6 +71,16 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { return aclcmdutil.BuildInstructions(errorCollection) } + if opts.InstanceID == "" { + + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } + + opts.InstanceID = kafkaInstance.GetId() + } + return runDelete(opts.InstanceID, opts) }, } @@ -277,20 +287,5 @@ func validateAndSetOpts(opts *aclcmdutil.CrudOptions) error { opts.Principal = serviceAccount } - if opts.InstanceID == "" { - cfg, err := opts.Config.Load() - if err != nil { - return err - } - - instanceID, ok := cfg.GetKafkaIdOk() - - if !ok { - return opts.Localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected") - } - - opts.InstanceID = instanceID - } - return nil } diff --git a/pkg/cmd/kafka/acl/flagutil/flagset.go b/pkg/cmd/kafka/acl/flagutil/flagset.go index 410c08838..d369dcc9d 100644 --- a/pkg/cmd/kafka/acl/flagutil/flagset.go +++ b/pkg/cmd/kafka/acl/flagutil/flagset.go @@ -3,6 +3,8 @@ package flagutil import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/aclcmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -25,7 +27,7 @@ var ResourceTypeFlagEntries = []*localize.TemplateEntry{ type flagSet struct { cmd *cobra.Command factory *factory.Factory - *flagutil.FlagSet + *kafkaflagutil.FlagSet } // NewFlagSet returns a new flag set with common Kafka ACL flags @@ -33,7 +35,7 @@ func NewFlagSet(cmd *cobra.Command, f *factory.Factory) *flagSet { return &flagSet{ cmd: cmd, factory: f, - FlagSet: flagutil.NewFlagSet(cmd, f.Localizer), + FlagSet: kafkaflagutil.NewFlagSet(cmd, f.Localizer), } } @@ -258,18 +260,6 @@ func (fs *flagSet) AddServiceAccount(serviceAccountID *string) *flagutil.FlagOpt return flagutil.WithFlagOptions(fs.cmd, flagName) } -// AddInstanceID adds a flag for the Kafka instance ID -func (fs *flagSet) AddInstanceID(id *string) { - flagName := "instance-id" - - fs.StringVar( - id, - flagName, - "", - fs.factory.Localizer.MustLocalize("kafka.common.flag.instanceID.description"), - ) -} - // AddAllAccounts adds a flag to set a wildcard for principals func (fs *flagSet) AddAllAccounts(allAccounts *bool) { flagName := "all-accounts" diff --git a/pkg/cmd/kafka/acl/grant/grant.go b/pkg/cmd/kafka/acl/grant/grant.go index 85d9061d7..f47202afb 100644 --- a/pkg/cmd/kafka/acl/grant/grant.go +++ b/pkg/cmd/kafka/acl/grant/grant.go @@ -7,13 +7,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/flagutil" "github.com/AlecAivazis/survey/v2" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -27,12 +28,12 @@ var ( ) type options struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext kafkaID string topic string @@ -49,12 +50,12 @@ type options struct { func NewGrantPermissionsACLCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -65,23 +66,17 @@ func NewGrantPermissionsACLCommand(f *factory.Factory) *cobra.Command { Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - if opts.kafkaID != "" { - return runGrantPermissions(opts) - } + if opts.kafkaID == "" { - cfg, err := opts.Config.Load() - if err != nil { - return err - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected") + opts.kafkaID = kafkaInstance.GetId() } - opts.kafkaID = instanceID - - if err = validateFlagInputCombination(opts); err != nil { + if err := validateFlagInputCombination(opts); err != nil { return err } diff --git a/pkg/cmd/kafka/acl/list/list.go b/pkg/cmd/kafka/acl/list/list.go index 4872f5e22..e5613dda0 100644 --- a/pkg/cmd/kafka/acl/list/list.go +++ b/pkg/cmd/kafka/acl/list/list.go @@ -5,13 +5,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/aclcmdutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -24,12 +25,12 @@ var ( ) type options struct { - config config.IConfig - connection factory.ConnectionFunc - logger logging.Logger - io *iostreams.IOStreams - localizer localize.Localizer - context context.Context + connection factory.ConnectionFunc + logger logging.Logger + io *iostreams.IOStreams + localizer localize.Localizer + context context.Context + serviceContext servicecontext.IContext page int32 size int32 @@ -43,16 +44,17 @@ type options struct { output string } +// nolint:funlen // NewListACLCommand creates a new command to list Kafka ACL rules func NewListACLCommand(f *factory.Factory) *cobra.Command { opts := &options{ - config: f.Config, - connection: f.Connection, - logger: f.Logger, - io: f.IOStreams, - localizer: f.Localizer, - context: f.Context, + connection: f.Connection, + logger: f.Logger, + io: f.IOStreams, + localizer: f.Localizer, + context: f.Context, + serviceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -71,22 +73,16 @@ func NewListACLCommand(f *factory.Factory) *cobra.Command { return opts.localizer.MustLocalizeError("kafka.common.validation.page.error.invalid.minValue", localize.NewEntry("Size", opts.size)) } - if opts.kafkaID != "" { - return runList(opts) - } + if opts.kafkaID == "" { - cfg, err := opts.config.Load() - if err != nil { - return err - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected") + opts.kafkaID = kafkaInstance.GetId() } - opts.kafkaID = instanceID - // user and service account can't be along with "--all-accounts" flag if allAccounts && (serviceAccount != "" || userID != "") { return opts.localizer.MustLocalizeError("kafka.acl.common.error.allAccountsCannotBeUsedWithUserFlag") @@ -116,7 +112,9 @@ func NewListACLCommand(f *factory.Factory) *cobra.Command { flags := flagutil.NewFlagSet(cmd, f) flags.AddInstanceID(&opts.kafkaID) - flags.AddOutput(&opts.output) + + table := dump.TableFormat + flags.AddOutputFormatted(&opts.output, true, &table) flags.AddPage(&opts.page) flags.AddSize(&opts.size) flags.AddUser(&userID) @@ -208,14 +206,12 @@ func runList(opts *options) (err error) { } switch opts.output { - case dump.EmptyFormat: + case dump.TableFormat: opts.logger.Info("") permissions := permissionsData.GetItems() rows := aclcmdutil.MapACLsToTableRows(permissions, opts.localizer) - dump.Table(opts.io.Out, rows) + return dump.Formatted(opts.io.Out, opts.output, rows) default: return dump.Formatted(opts.io.Out, opts.output, permissionsData) } - - return nil } diff --git a/pkg/cmd/kafka/consumergroup/delete/delete.go b/pkg/cmd/kafka/consumergroup/delete/delete.go index 6773c5ff1..bbced1997 100644 --- a/pkg/cmd/kafka/consumergroup/delete/delete.go +++ b/pkg/cmd/kafka/consumergroup/delete/delete.go @@ -4,14 +4,15 @@ import ( "context" "net/http" - "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/AlecAivazis/survey/v2" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -22,23 +23,23 @@ type options struct { id string skipConfirm bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDeleteConsumerGroupCommand gets a new command for deleting a consumer group. func NewDeleteConsumerGroupCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - IO: f.IOStreams, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -52,25 +53,21 @@ func NewDeleteConsumerGroupCommand(f *factory.Factory) *cobra.Command { return runCmd(opts) } - cfg, err := opts.Config.Load() + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.consumerGroup.common.error.noKafkaSelected") - } - - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) flags.AddYes(&opts.skipConfirm) + flags.AddInstanceID(&opts.kafkaID) flags.StringVar(&opts.id, "id", "", opts.localizer.MustLocalize("kafka.consumerGroup.common.flag.id.description", localize.NewEntry("Action", "delete"))) _ = cmd.MarkFlagRequired("id") diff --git a/pkg/cmd/kafka/consumergroup/describe/describe.go b/pkg/cmd/kafka/consumergroup/describe/describe.go index 2c4794ae8..f561c3b89 100644 --- a/pkg/cmd/kafka/consumergroup/describe/describe.go +++ b/pkg/cmd/kafka/consumergroup/describe/describe.go @@ -7,14 +7,15 @@ import ( "net/http" "sort" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -27,11 +28,11 @@ type options struct { outputFormat string id string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } type consumerRow struct { @@ -46,11 +47,11 @@ type consumerRow struct { // NewDescribeConsumerGroupCommand gets a new command for describing a consumer group. func NewDescribeConsumerGroupCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ Use: "describe", @@ -69,17 +70,12 @@ func NewDescribeConsumerGroupCommand(f *factory.Factory) *cobra.Command { return runCmd(opts) } - cfg, err := opts.Config.Load() + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.consumerGroup.common.error.noKafkaSelected") - } - - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() return runCmd(opts) }, diff --git a/pkg/cmd/kafka/consumergroup/list/list.go b/pkg/cmd/kafka/consumergroup/list/list.go index 63a0f7b59..e3e1b9232 100644 --- a/pkg/cmd/kafka/consumergroup/list/list.go +++ b/pkg/cmd/kafka/consumergroup/list/list.go @@ -4,15 +4,18 @@ import ( "context" "net/http" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -23,12 +26,12 @@ import ( ) type options struct { - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - IO *iostreams.IOStreams - localizer localize.Localizer - Context context.Context + Connection factory.ConnectionFunc + Logger logging.Logger + IO *iostreams.IOStreams + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext output string kafkaID string @@ -47,12 +50,12 @@ type consumerGroupRow struct { // NewListConsumerGroupCommand creates a new command to list consumer groups func NewListConsumerGroupCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -62,8 +65,8 @@ func NewListConsumerGroupCommand(f *factory.Factory) *cobra.Command { Example: opts.localizer.MustLocalize("kafka.consumerGroup.list.cmd.example"), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - if opts.output != "" && !flagutil.IsValidInput(opts.output, flagutil.ValidOutputFormats...) { - return flagutil.InvalidValueError("output", opts.output, flagutil.ValidOutputFormats...) + if opts.output != "" && !flagutil.IsValidInput(opts.output, flagutil.ValidListOutputFormats...) { + return flagutil.InvalidValueError("output", opts.output, flagutil.ValidListOutputFormats...) } if opts.page < 1 { @@ -74,25 +77,26 @@ func NewListConsumerGroupCommand(f *factory.Factory) *cobra.Command { return opts.localizer.MustLocalizeError("kafka.common.validation.size.error.invalid.minValue", localize.NewEntry("Size", opts.size)) } - cfg, err := opts.Config.Load() - if err != nil { - return err - } + if opts.kafkaID == "" { - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.consumerGroup.common.error.noKafkaSelected") - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() + } return runList(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) + + flags.AddInstanceID(&opts.kafkaID) - flags.AddOutput(&opts.output) + table := dump.TableFormat + flags.AddOutputFormatted(&opts.output, true, &table) flags.StringVar(&opts.topic, "topic", "", opts.localizer.MustLocalize("kafka.consumerGroup.list.flag.topic.description")) flags.StringVar(&opts.search, "search", "", opts.localizer.MustLocalize("kafka.consumerGroup.list.flag.search")) flags.Int32VarP(&opts.page, "page", "", cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber), opts.localizer.MustLocalize("kafka.consumerGroup.list.flag.page")) @@ -162,16 +166,14 @@ func runList(opts *options) (err error) { } switch opts.output { - case dump.EmptyFormat: + case dump.TableFormat: opts.Logger.Info("") consumerGroups := consumerGroupData.GetItems() rows := mapConsumerGroupResultsToTableFormat(consumerGroups) - dump.Table(opts.IO.Out, rows) + return dump.Formatted(opts.IO.Out, opts.output, rows) default: return dump.Formatted(opts.IO.Out, opts.output, consumerGroupData) } - - return nil } func mapConsumerGroupResultsToTableFormat(consumerGroups []kafkainstanceclient.ConsumerGroup) []consumerGroupRow { diff --git a/pkg/cmd/kafka/consumergroup/resetoffset/reset_offset.go b/pkg/cmd/kafka/consumergroup/resetoffset/reset_offset.go index 9560245a9..056b22ac0 100644 --- a/pkg/cmd/kafka/consumergroup/resetoffset/reset_offset.go +++ b/pkg/cmd/kafka/consumergroup/resetoffset/reset_offset.go @@ -5,15 +5,17 @@ import ( "net/http" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/consumergroup/groupcmdutil" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/AlecAivazis/survey/v2" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -29,12 +31,12 @@ type options struct { topic string partitions []int32 - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } var validator groupcmdutil.Validator @@ -42,12 +44,12 @@ var validator groupcmdutil.Validator // NewResetOffsetConsumerGroupCommand gets a new command for resetting offset for a consumer group. func NewResetOffsetConsumerGroupCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - IO: f.IOStreams, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -75,25 +77,21 @@ func NewResetOffsetConsumerGroupCommand(f *factory.Factory) *cobra.Command { return runCmd(opts) } - cfg, err := opts.Config.Load() + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.consumerGroup.common.error.noKafkaSelected") - } - - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) flags.AddYes(&opts.skipConfirm) + flags.AddInstanceID(&opts.kafkaID) flags.StringVar(&opts.id, "id", "", opts.localizer.MustLocalize("kafka.consumerGroup.common.flag.id.description", localize.NewEntry("Action", "reset-offset"))) flags.StringVar(&opts.value, "value", "", opts.localizer.MustLocalize("kafka.consumerGroup.resetOffset.flag.value")) flags.StringVar(&opts.offset, "offset", "", opts.localizer.MustLocalize("kafka.consumerGroup.resetOffset.flag.offset")) diff --git a/pkg/cmd/kafka/create/create.go b/pkg/cmd/kafka/create/create.go index 3f80b84ec..4d6cad19d 100644 --- a/pkg/cmd/kafka/create/create.go +++ b/pkg/cmd/kafka/create/create.go @@ -11,13 +11,13 @@ import ( kafkaFlagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/kafkacmdutil" "github.com/redhat-developer/app-services-cli/pkg/shared/accountmgmtutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/remote" "github.com/redhat-developer/app-services-cli/pkg/shared/svcstatus" "k8s.io/utils/strings/slices" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" @@ -25,6 +25,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/spinner" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" @@ -51,12 +52,12 @@ type options struct { wait bool bypassAmsCheck bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } const ( @@ -69,12 +70,12 @@ const ( // NewCreateCommand creates a new command for creating kafkas. func NewCreateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, multiAZ: defaultMultiAZ, } @@ -137,7 +138,12 @@ func NewCreateCommand(f *factory.Factory) *cobra.Command { // nolint:funlen func runCreate(opts *options) error { - cfg, err := opts.Config.Load() + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -173,7 +179,7 @@ func runCreate(opts *options) error { if opts.interactive { opts.Logger.Debug() - payload, err = promptKafkaPayload(opts, constants) + payload, err = promptKafkaPayload(opts) if err != nil { return err } @@ -189,7 +195,7 @@ func runCreate(opts *options) error { } if !opts.bypassAmsCheck { - err = validateProviderAndRegion(opts, constants, conn) + err = validateProviderAndRegion(opts, conn) if err != nil { return err } @@ -223,6 +229,8 @@ func runCreate(opts *options) error { return opts.localizer.MustLocalizeError("kafka.create.error.temporary.unavailable") case kafkamgmtv1errors.ERROR_36: return opts.localizer.MustLocalizeError("kafka.create.error.conflictError", localize.NewEntry("Name", payload.Name)) + case kafkamgmtv1errors.ERROR_41: + return opts.localizer.MustLocalizeError("kafka.create.error.notsupported", localize.NewEntry("Name", payload.Name)) } } @@ -230,14 +238,12 @@ func runCreate(opts *options) error { return err } - kafkaCfg := &config.KafkaConfig{ - ClusterID: response.GetId(), - } - if opts.autoUse { opts.Logger.Debug("Auto-use is set, updating the current instance") - cfg.Services.Kafka = kafkaCfg - if err = opts.Config.Save(cfg); err != nil { + currCtx.KafkaID = response.GetId() + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err = opts.ServiceContext.Save(svcContext); err != nil { return fmt.Errorf("%v: %w", opts.localizer.MustLocalize("kafka.common.error.couldNotUseKafka"), err) } } else { @@ -297,7 +303,7 @@ func runCreate(opts *options) error { return nil } -func validateProviderAndRegion(opts *options, constants *remote.DynamicServiceConstants, conn connection.Connection) error { +func validateProviderAndRegion(opts *options, conn connection.Connection) error { opts.Logger.Debug("Validating provider and region") cloudProviders, _, err := conn.API(). KafkaMgmt(). @@ -328,11 +334,11 @@ func validateProviderAndRegion(opts *options, constants *remote.DynamicServiceCo validProvidersEntry := localize.NewEntry("Providers", providers) return opts.localizer.MustLocalizeError("kafka.create.provider.error.invalidProvider", providerEntry, validProvidersEntry) } - - return validateProviderRegion(conn, opts, selectedProvider, constants) + // Temporary disabled due to breaking changes in the API + return nil // validateProviderRegion(conn, opts, selectedProvider, constants) } -func validateProviderRegion(conn connection.Connection, opts *options, selectedProvider kafkamgmtclient.CloudProvider, constants *remote.DynamicServiceConstants) error { +func ValidateProviderRegion(conn connection.Connection, opts *options, selectedProvider kafkamgmtclient.CloudProvider, constants *remote.DynamicServiceConstants) error { cloudRegion, _, err := conn.API(). KafkaMgmt(). GetCloudProviderRegions(opts.Context, selectedProvider.GetId()). @@ -399,7 +405,7 @@ type promptAnswers struct { } // Show a prompt to allow the user to interactively insert the data for their Kafka -func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants) (payload *kafkamgmtclient.KafkaRequestPayload, err error) { +func promptKafkaPayload(opts *options) (payload *kafkamgmtclient.KafkaRequestPayload, err error) { conn, err := opts.Connection(connection.DefaultConfigSkipMasAuth) if err != nil { return nil, err @@ -458,14 +464,15 @@ func promptKafkaPayload(opts *options, constants *remote.DynamicServiceConstants return nil, err } - userInstanceTypes, err := accountmgmtutil.GetUserSupportedInstanceTypes(opts.Context, constants.Kafka.Ams, conn) - if err != nil { - opts.Logger.Debug("Cannot retrieve user supported instance types. Skipping validation", err) - return payload, err - } + // Temporary disabled due to breaking changes in the API + // userInstanceTypes, err := accountmgmtutil.GetUserSupportedInstanceTypes(opts.Context, constants.Kafka.Ams, conn) + // if err != nil { + // opts.Logger.Debug("Cannot retrieve user supported instance types. Skipping validation", err) + // return payload, err + // } regions := cloudRegionResponse.GetItems() - regionIDs := pkgKafka.GetEnabledCloudRegionIDs(regions, &userInstanceTypes) + regionIDs := pkgKafka.GetEnabledCloudRegionIDs(regions, nil) regionPrompt := &survey.Select{ Message: opts.localizer.MustLocalize("kafka.create.input.cloudRegion.message"), diff --git a/pkg/cmd/kafka/delete/delete.go b/pkg/cmd/kafka/delete/delete.go index 1b60ea053..544d32c7c 100644 --- a/pkg/cmd/kafka/delete/delete.go +++ b/pkg/cmd/kafka/delete/delete.go @@ -5,12 +5,13 @@ import ( "fmt" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -24,23 +25,23 @@ type options struct { name string skipConfirm bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDeleteCommand command for deleting kafkas. func NewDeleteCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -62,16 +63,12 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { return runDelete(opts) } - cfg, err := opts.Config.Load() + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.common.error.noKafkaSelected") - } - opts.id = instanceID + opts.id = kafkaInstance.GetId() return runDelete(opts) }, @@ -91,7 +88,12 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { } func runDelete(opts *options) error { - cfg, err := opts.Config.Load() + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -147,17 +149,18 @@ func runDelete(opts *options) error { opts.Logger.Info(opts.localizer.MustLocalize("kafka.delete.log.info.deleting", localize.NewEntry("Name", kafkaName))) - currentKafka := cfg.Services.Kafka - // this is not the current cluster, our work here is done - if currentKafka == nil || currentKafka.ClusterID != response.GetId() { + currentKafka := currCtx.KafkaID + // this is not the current instance, our work here is done + if currentKafka != response.GetId() { return nil } // the Kafka that was deleted is set as the user's current cluster - // since it was deleted it should be removed from the config - cfg.Services.Kafka = nil - err = opts.Config.Save(cfg) - if err != nil { + // since it was deleted it should be removed from the context + currCtx.KafkaID = "" + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err := opts.ServiceContext.Save(svcContext); err != nil { return err } diff --git a/pkg/cmd/kafka/describe/describe.go b/pkg/cmd/kafka/describe/describe.go index c17344a03..626862ac6 100644 --- a/pkg/cmd/kafka/describe/describe.go +++ b/pkg/cmd/kafka/describe/describe.go @@ -6,12 +6,13 @@ import ( "net/http" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -24,24 +25,24 @@ type options struct { bootstrapServer bool outputFormat string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDescribeCommand describes a Kafka instance, either by passing an `--id flag` -// or by using the kafka instance set in the config, if any +// or by using the kafka instance set in the current context, if any func NewDescribeCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -64,18 +65,12 @@ func NewDescribeCommand(f *factory.Factory) *cobra.Command { return runDescribe(opts) } - cfg, err := opts.Config.Load() + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.common.error.noKafkaSelected") - } - opts.id = instanceID - - opts.id = cfg.Services.Kafka.ClusterID + opts.id = kafkaInstance.GetId() return runDescribe(opts) }, diff --git a/pkg/cmd/kafka/flagutil/flagutil.go b/pkg/cmd/kafka/flagutil/flagutil.go index 7eade338b..5641f2b13 100644 --- a/pkg/cmd/kafka/flagutil/flagutil.go +++ b/pkg/cmd/kafka/flagutil/flagutil.go @@ -14,7 +14,7 @@ const ( FlagRegion = "region" ) -type flagSet struct { +type FlagSet struct { flags *pflag.FlagSet cmd *cobra.Command localizer localize.Localizer @@ -22,8 +22,8 @@ type flagSet struct { } // NewFlagSet returns a new flag set for creating common Kafka-command flags -func NewFlagSet(cmd *cobra.Command, localizer localize.Localizer) *flagSet { - return &flagSet{ +func NewFlagSet(cmd *cobra.Command, localizer localize.Localizer) *FlagSet { + return &FlagSet{ cmd: cmd, flags: cmd.Flags(), localizer: localizer, @@ -32,7 +32,7 @@ func NewFlagSet(cmd *cobra.Command, localizer localize.Localizer) *flagSet { } // AddInstanceID adds a flag for setting the Kafka instance ID -func (fs *flagSet) AddInstanceID(instanceID *string) { +func (fs *FlagSet) AddInstanceID(instanceID *string) { flagName := "instance-id" fs.flags.StringVar( diff --git a/pkg/cmd/kafka/list/list.go b/pkg/cmd/kafka/list/list.go index f877989eb..e04ee591b 100644 --- a/pkg/cmd/kafka/list/list.go +++ b/pkg/cmd/kafka/list/list.go @@ -10,13 +10,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -42,26 +43,26 @@ type options struct { limit int search string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewListCommand creates a new command for listing kafkas. func NewListCommand(f *factory.Factory) *cobra.Command { opts := &options{ - page: 0, - limit: 100, - search: "", - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + page: 0, + limit: 100, + search: "", + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -71,8 +72,8 @@ func NewListCommand(f *factory.Factory) *cobra.Command { Example: opts.localizer.MustLocalize("kafka.list.cmd.example"), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { - return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidListOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidListOutputFormats...) } validator := &kafkacmdutil.Validator{ @@ -89,7 +90,8 @@ func NewListCommand(f *factory.Factory) *cobra.Command { flags := kafkaFlagutil.NewFlagSet(cmd, opts.localizer) - flags.AddOutput(&opts.outputFormat) + table := dump.TableFormat + flags.AddOutputFormatted(&opts.outputFormat, true, &table) flags.IntVar(&opts.page, "page", int(cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber)), opts.localizer.MustLocalize("kafka.list.flag.page")) flags.IntVar(&opts.limit, "limit", 100, opts.localizer.MustLocalize("kafka.list.flag.limit")) flags.StringVar(&opts.search, "search", "", opts.localizer.MustLocalize("kafka.list.flag.search")) @@ -126,20 +128,28 @@ func runList(opts *options) error { } switch opts.outputFormat { - case dump.EmptyFormat: + case dump.TableFormat: var rows []kafkaRow - serviceConfig, _ := opts.Config.Load() - if serviceConfig != nil && serviceConfig.Services.Kafka != nil { - rows = mapResponseItemsToRows(response.GetItems(), serviceConfig.Services.Kafka.ClusterID) + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) + if err != nil { + return err + } + + if currCtx.KafkaID != "" { + rows = mapResponseItemsToRows(response.GetItems(), currCtx.KafkaID) } else { rows = mapResponseItemsToRows(response.GetItems(), "-") } - dump.Table(opts.IO.Out, rows) opts.Logger.Info("") + return dump.Formatted(opts.IO.Out, opts.outputFormat, rows) default: return dump.Formatted(opts.IO.Out, opts.outputFormat, response) } - return nil } func mapResponseItemsToRows(kafkas []kafkamgmtclient.KafkaRequest, selectedId string) []kafkaRow { diff --git a/pkg/cmd/kafka/topic/create/create.go b/pkg/cmd/kafka/topic/create/create.go index 1bf9de913..138df281c 100644 --- a/pkg/cmd/kafka/topic/create/create.go +++ b/pkg/cmd/kafka/topic/create/create.go @@ -5,14 +5,16 @@ import ( "net/http" "strconv" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/topic/topiccmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -37,23 +39,23 @@ type options struct { cleanupPolicy string interactive bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewCreateTopicCommand gets a new command for creating kafka topic. func NewCreateTopicCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -82,48 +84,27 @@ func NewCreateTopicCommand(f *factory.Factory) *cobra.Command { } if !opts.interactive { - validator := topiccmdutil.Validator{ - Localizer: opts.localizer, - } - - if err = validator.ValidateName(opts.topicName); err != nil { - return err - } - - if err = validator.ValidatePartitionsN(opts.partitions); err != nil { + err = validateProperties(opts) + if err != nil { return err } + } - if err = validator.ValidateMessageRetentionPeriod(opts.retentionMs); err != nil { - return err - } + if opts.kafkaID == "" { - if err = validator.ValidateMessageRetentionSize(opts.retentionBytes); err != nil { + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { return err } - } - - if opts.kafkaID != "" { - return runCmd(opts) - } - - cfg, err := opts.Config.Load() - if err != nil { - return err - } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.topic.common.error.noKafkaSelected") + opts.kafkaID = kafkaInstance.GetId() } - opts.kafkaID = instanceID - return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) flags.StringVar(&opts.topicName, "name", "", opts.localizer.MustLocalize("kafka.topic.common.flag.name.description")) flags.Int32Var(&opts.partitions, "partitions", 1, opts.localizer.MustLocalize("kafka.topic.common.input.partitions.description")) @@ -131,6 +112,7 @@ func NewCreateTopicCommand(f *factory.Factory) *cobra.Command { flags.IntVar(&opts.retentionBytes, "retention-bytes", defaultRetentionSize, opts.localizer.MustLocalize("kafka.topic.common.input.retentionBytes.description")) flags.StringVar(&opts.cleanupPolicy, "cleanup-policy", defaultCleanupPolicy, opts.localizer.MustLocalize("kafka.topic.common.input.cleanupPolicy.description")) flags.AddOutput(&opts.outputFormat) + flags.AddInstanceID(&opts.kafkaID) flagutil.EnableOutputFlagCompletion(cmd) flagutil.EnableStaticFlagCompletion(cmd, "cleanup-policy", topiccmdutil.ValidCleanupPolicies) @@ -286,3 +268,27 @@ func createConfigEntries(opts *options) *[]kafkainstanceclient.ConfigEntry { } return topiccmdutil.CreateConfigEntries(configEntryMap) } + +func validateProperties(opts *options) (err error) { + validator := topiccmdutil.Validator{ + Localizer: opts.localizer, + } + + if err = validator.ValidateName(opts.topicName); err != nil { + return err + } + + if err = validator.ValidatePartitionsN(opts.partitions); err != nil { + return err + } + + if err = validator.ValidateMessageRetentionPeriod(opts.retentionMs); err != nil { + return err + } + + if err = validator.ValidateMessageRetentionSize(opts.retentionBytes); err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/kafka/topic/delete/delete.go b/pkg/cmd/kafka/topic/delete/delete.go index 09bf09a2a..79ec217b4 100644 --- a/pkg/cmd/kafka/topic/delete/delete.go +++ b/pkg/cmd/kafka/topic/delete/delete.go @@ -4,14 +4,16 @@ import ( "context" "net/http" - "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/AlecAivazis/survey/v2" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -22,23 +24,23 @@ type options struct { kafkaID string force bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDeleteTopicCommand gets a new command for deleting a kafka topic. func NewDeleteTopicCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -52,27 +54,21 @@ func NewDeleteTopicCommand(f *factory.Factory) *cobra.Command { return opts.localizer.MustLocalizeError("flag.error.requiredWhenNonInteractive", localize.NewEntry("Flag", "yes")) } - if opts.kafkaID != "" { - return runCmd(opts) - } + if opts.kafkaID == "" { - cfg, err := opts.Config.Load() - if err != nil { - return err - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.topic.common.error.noKafkaSelected") + opts.kafkaID = kafkaInstance.GetId() } - opts.kafkaID = instanceID - return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) flags.StringVar(&opts.topicName, "name", "", opts.localizer.MustLocalize("kafka.topic.common.flag.name.description")) @@ -82,6 +78,7 @@ func NewDeleteTopicCommand(f *factory.Factory) *cobra.Command { return kafkacmdutil.FilterValidTopicNameArgs(f, toComplete) }) flags.AddYes(&opts.force) + flags.AddInstanceID(&opts.kafkaID) return cmd } diff --git a/pkg/cmd/kafka/topic/describe/describe.go b/pkg/cmd/kafka/topic/describe/describe.go index c0472c784..f7240e4f7 100644 --- a/pkg/cmd/kafka/topic/describe/describe.go +++ b/pkg/cmd/kafka/topic/describe/describe.go @@ -4,14 +4,16 @@ import ( "context" "net/http" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -22,23 +24,23 @@ type options struct { kafkaID string outputFormat string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDescribeTopicCommand gets a new command for describing a kafka topic. func NewDescribeTopicCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -54,29 +56,24 @@ func NewDescribeTopicCommand(f *factory.Factory) *cobra.Command { } } - if opts.kafkaID != "" { - return runCmd(opts) - } + if opts.kafkaID == "" { - cfg, err := opts.Config.Load() - if err != nil { - return err - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.topic.common.error.noKafkaSelected") + opts.kafkaID = kafkaInstance.GetId() } - opts.kafkaID = instanceID - return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) flags.AddOutput(&opts.outputFormat) + flags.AddInstanceID(&opts.kafkaID) flags.StringVar(&opts.name, "name", "", opts.localizer.MustLocalize("kafka.topic.common.flag.output.description")) _ = cmd.RegisterFlagCompletionFunc("name", func(cmd *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/pkg/cmd/kafka/topic/list/list.go b/pkg/cmd/kafka/topic/list/list.go index f3d4a54fb..0aa0f59e4 100644 --- a/pkg/cmd/kafka/topic/list/list.go +++ b/pkg/cmd/kafka/topic/list/list.go @@ -4,15 +4,17 @@ import ( "context" "net/http" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/topic/topiccmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -22,12 +24,12 @@ import ( ) type options struct { - Config config.IConfig - IO *iostreams.IOStreams - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext kafkaID string output string @@ -46,12 +48,12 @@ type topicRow struct { // NewListTopicCommand gets a new command for getting kafkas. func NewListTopicCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -62,7 +64,7 @@ func NewListTopicCommand(f *factory.Factory) *cobra.Command { Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { if opts.output != "" { - if err := flagutil.ValidateOutput(opts.output); err != nil { + if err := flagutil.ValidateOutputForTable(opts.output); err != nil { return err } } @@ -84,25 +86,24 @@ func NewListTopicCommand(f *factory.Factory) *cobra.Command { } } - cfg, err := opts.Config.Load() - if err != nil { - return err - } + if opts.kafkaID == "" { - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.topic.common.error.noKafkaSelected") - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() + } return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) - flags.AddOutput(&opts.output) + table := dump.TableFormat + flags.AddOutputFormatted(&opts.output, true, &table) flags.StringVar(&opts.search, "search", "", opts.localizer.MustLocalize("kafka.topic.list.flag.search.description")) flags.Int32VarP(&opts.page, "page", "", cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber), opts.localizer.MustLocalize("kafka.topic.list.flag.page.description")) flags.Int32VarP(&opts.size, "size", "", cmdutil.ConvertSizeValueToInt32(build.DefaultPageSize), opts.localizer.MustLocalize("kafka.topic.list.flag.size.description")) @@ -167,15 +168,13 @@ func runCmd(opts *options) error { stdout := opts.IO.Out switch opts.output { - case dump.EmptyFormat: + case dump.TableFormat: topics := topicData.GetItems() rows := mapTopicResultsToTableFormat(topics) - dump.Table(stdout, rows) + return dump.Formatted(stdout, opts.output, rows) default: return dump.Formatted(stdout, opts.output, topicData) } - - return nil } func mapTopicResultsToTableFormat(topics []kafkainstanceclient.Topic) []topicRow { diff --git a/pkg/cmd/kafka/topic/update/update.go b/pkg/cmd/kafka/topic/update/update.go index 77410c31f..67f5f91b5 100644 --- a/pkg/cmd/kafka/topic/update/update.go +++ b/pkg/cmd/kafka/topic/update/update.go @@ -5,15 +5,18 @@ import ( "net/http" "strings" + kafkaflagutil "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/topic/topiccmdutil" kafkacmdutil "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/AlecAivazis/survey/v2" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" @@ -36,24 +39,24 @@ type options struct { interactive bool cleanupPolicy string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewUpdateTopicCommand gets a new command for updating a kafka topic. // nolint:funlen func NewUpdateTopicCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Connection: f.Connection, - Config: f.Config, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -128,23 +131,23 @@ func NewUpdateTopicCommand(f *factory.Factory) *cobra.Command { } } - cfg, err := opts.Config.Load() - if err != nil { - return err - } + if opts.kafkaID == "" { - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.topic.common.error.noKafkaSelected") - } + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err + } - opts.kafkaID = instanceID + opts.kafkaID = kafkaInstance.GetId() + } return runCmd(opts) }, } - flags := flagutil.NewFlagSet(cmd, opts.localizer) + flags := kafkaflagutil.NewFlagSet(cmd, opts.localizer) + + flags.AddInstanceID(&opts.kafkaID) flags.StringVar(&opts.retentionMsStr, "retention-ms", "", opts.localizer.MustLocalize("kafka.topic.common.input.retentionMs.description")) flags.StringVar(&opts.retentionBytesStr, "retention-bytes", "", opts.localizer.MustLocalize("kafka.topic.common.input.retentionBytes.description")) diff --git a/pkg/cmd/kafka/update/update.go b/pkg/cmd/kafka/update/update.go index e138812d9..4367cfd37 100644 --- a/pkg/cmd/kafka/update/update.go +++ b/pkg/cmd/kafka/update/update.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/redhat-developer/app-services-cli/pkg/core/auth/token" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/AlecAivazis/survey/v2" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" @@ -19,6 +20,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -41,22 +43,25 @@ type options struct { userIsOrgAdmin bool reauth flagutil.Tribool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Config config.IConfig + Connection factory.ConnectionFunc + logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } +// nolint:funlen func NewUpdateCommand(f *factory.Factory) *cobra.Command { opts := options{ - IO: f.IOStreams, - Config: f.Config, - localizer: f.Localizer, - logger: f.Logger, - Connection: f.Connection, - Context: f.Context, + IO: f.IOStreams, + Config: f.Config, + localizer: f.Localizer, + logger: f.Logger, + Connection: f.Connection, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -102,11 +107,12 @@ func NewUpdateCommand(f *factory.Factory) *cobra.Command { return run(&opts) } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { - return opts.localizer.MustLocalizeError("kafka.common.error.noKafkaSelected") + kafkaInstance, err := contextutil.GetCurrentKafkaInstance(f) + if err != nil { + return err } - opts.id = instanceID + + opts.id = kafkaInstance.GetId() return run(&opts) }, diff --git a/pkg/cmd/kafka/use/use.go b/pkg/cmd/kafka/use/use.go index fc62f43e1..6119904ed 100644 --- a/pkg/cmd/kafka/use/use.go +++ b/pkg/cmd/kafka/use/use.go @@ -6,12 +6,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -24,22 +25,22 @@ type options struct { name string interactive bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewUseCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -89,7 +90,12 @@ func runUse(opts *options) error { } } - cfg, err := opts.Config.Load() + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -114,14 +120,11 @@ func runUse(opts *options) error { } } - // build Kafka config object from the response - var kafkaConfig = config.KafkaConfig{ - ClusterID: res.GetId(), - } - nameTmplEntry := localize.NewEntry("Name", res.GetName()) - cfg.Services.Kafka = &kafkaConfig - if err := opts.Config.Save(cfg); err != nil { + currCtx.KafkaID = res.GetId() + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err := opts.ServiceContext.Save(svcContext); err != nil { saveErrMsg := opts.localizer.MustLocalize("kafka.use.error.saveError", nameTmplEntry) return fmt.Errorf("%v: %w", saveErrMsg, err) } diff --git a/pkg/cmd/registry/artifact/crud/create/create.go b/pkg/cmd/registry/artifact/crud/create/create.go index cdf789456..c670ba1da 100644 --- a/pkg/cmd/registry/artifact/crud/create/create.go +++ b/pkg/cmd/registry/artifact/crud/create/create.go @@ -8,13 +8,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" @@ -36,22 +37,22 @@ type options struct { registryID string outputFormat string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewCreateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -80,17 +81,12 @@ func NewCreateCommand(f *factory.Factory) *cobra.Command { return runCreate(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runCreate(opts) }, } @@ -153,7 +149,7 @@ func runCreate(opts *options) error { } } } else { - opts.Logger.Info(opts.localizer.MustLocalize("artifact.common.message.reading.file")) + opts.Logger.Info(opts.localizer.MustLocalize("common.message.reading.file")) specifiedFile, err = util.CreateFileFromStdin() if err != nil { return err diff --git a/pkg/cmd/registry/artifact/crud/delete/delete.go b/pkg/cmd/registry/artifact/crud/delete/delete.go index 4cb6c8ede..de62dfc9f 100644 --- a/pkg/cmd/registry/artifact/crud/delete/delete.go +++ b/pkg/cmd/registry/artifact/crud/delete/delete.go @@ -7,11 +7,12 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" ) @@ -23,22 +24,22 @@ type options struct { registryID string force bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewDeleteCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -56,17 +57,12 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { return runDelete(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runDelete(opts) }, } diff --git a/pkg/cmd/registry/artifact/crud/get/get.go b/pkg/cmd/registry/artifact/crud/get/get.go index 2ff1719f4..af704cba1 100644 --- a/pkg/cmd/registry/artifact/crud/get/get.go +++ b/pkg/cmd/registry/artifact/crud/get/get.go @@ -8,12 +8,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -27,22 +28,22 @@ type options struct { registryID string version string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewGetCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -60,17 +61,12 @@ func NewGetCommand(f *factory.Factory) *cobra.Command { return runGet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runGet(opts) }, } diff --git a/pkg/cmd/registry/artifact/crud/list/list.go b/pkg/cmd/registry/artifact/crud/list/list.go index 2e8d8fd2c..6cd3a54d6 100644 --- a/pkg/cmd/registry/artifact/crud/list/list.go +++ b/pkg/cmd/registry/artifact/crud/list/list.go @@ -6,12 +6,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" @@ -47,23 +48,23 @@ type options struct { page int32 limit int32 - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewListCommand creates a new command for listing registry artifacts. func NewListCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -81,22 +82,15 @@ func NewListCommand(f *factory.Factory) *cobra.Command { return opts.localizer.MustLocalizeError("artifact.common.error.page.and.limit.too.small") } - if opts.registryID != "" { - return runList(opts) - } - - cfg, err := opts.Config.Load() - if err != nil { - return err - } + if opts.registryID == "" { + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err + } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") + opts.registryID = registryInstance.GetId() } - opts.registryID = instanceID - return runList(opts) }, } @@ -169,15 +163,14 @@ func runList(opts *options) error { } switch opts.outputFormat { - case dump.EmptyFormat: + case dump.TableFormat: rows := mapResponseItemsToRows(response.Artifacts) - dump.Table(opts.IO.Out, rows) opts.Logger.Info("") + return dump.Formatted(opts.IO.Out, opts.outputFormat, rows) default: return dump.Formatted(opts.IO.Out, opts.outputFormat, response) } - return nil } func mapResponseItemsToRows(artifacts []registryinstanceclient.SearchedArtifact) []artifactRow { diff --git a/pkg/cmd/registry/artifact/crud/update/update.go b/pkg/cmd/registry/artifact/crud/update/update.go index 1abc9c363..147c63ca4 100644 --- a/pkg/cmd/registry/artifact/crud/update/update.go +++ b/pkg/cmd/registry/artifact/crud/update/update.go @@ -7,11 +7,12 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -29,23 +30,23 @@ type options struct { name string description string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewUpdateCommand creates a new command for updating binary content of registry artifacts. func NewUpdateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -67,17 +68,12 @@ func NewUpdateCommand(f *factory.Factory) *cobra.Command { return runUpdate(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runUpdate(opts) }, } @@ -128,7 +124,7 @@ func runUpdate(opts *options) error { } } } else { - opts.Logger.Info(opts.localizer.MustLocalize("artifact.common.message.reading.file")) + opts.Logger.Info(opts.localizer.MustLocalize("common.message.reading.file")) specifiedFile, err = util.CreateFileFromStdin() if err != nil { return err diff --git a/pkg/cmd/registry/artifact/download/download.go b/pkg/cmd/registry/artifact/download/download.go index c133c6ce4..dfc095634 100644 --- a/pkg/cmd/registry/artifact/download/download.go +++ b/pkg/cmd/registry/artifact/download/download.go @@ -8,12 +8,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -31,23 +32,23 @@ type options struct { registryID string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewDownloadCommand creates a new command for downloading binary content for registry artifacts. func NewDownloadCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -61,17 +62,12 @@ func NewDownloadCommand(f *factory.Factory) *cobra.Command { return runGet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runGet(opts) }, } diff --git a/pkg/cmd/registry/artifact/metadata/get.go b/pkg/cmd/registry/artifact/metadata/get.go index e6113b1ce..1e866f428 100644 --- a/pkg/cmd/registry/artifact/metadata/get.go +++ b/pkg/cmd/registry/artifact/metadata/get.go @@ -6,14 +6,15 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/color" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" "github.com/spf13/cobra" @@ -26,23 +27,23 @@ type GetOptions struct { registryID string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewGetMetadataCommand creates a new command for fetching metadata for registry artifacts. func NewGetMetadataCommand(f *factory.Factory) *cobra.Command { opts := &GetOptions{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -60,17 +61,12 @@ func NewGetMetadataCommand(f *factory.Factory) *cobra.Command { return runGet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runGet(opts) }, } diff --git a/pkg/cmd/registry/artifact/metadata/set.go b/pkg/cmd/registry/artifact/metadata/set.go index 84f3a3beb..5725be201 100644 --- a/pkg/cmd/registry/artifact/metadata/set.go +++ b/pkg/cmd/registry/artifact/metadata/set.go @@ -6,13 +6,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/editor" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -29,23 +30,23 @@ type SetOptions struct { name string description string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewSetMetadataCommand creates a new command for updating metadata for registry artifacts. func NewSetMetadataCommand(f *factory.Factory) *cobra.Command { opts := &SetOptions{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -67,17 +68,12 @@ func NewSetMetadataCommand(f *factory.Factory) *cobra.Command { return runSet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runSet(opts) }, } diff --git a/pkg/cmd/registry/artifact/migrate/export.go b/pkg/cmd/registry/artifact/migrate/export.go index 53796dda6..0f7ae1f34 100644 --- a/pkg/cmd/registry/artifact/migrate/export.go +++ b/pkg/cmd/registry/artifact/migrate/export.go @@ -6,11 +6,12 @@ import ( "os" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -20,22 +21,22 @@ type ExportOptions struct { file string registryID string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewExportCommand(f *factory.Factory) *cobra.Command { opts := &ExportOptions{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -49,17 +50,12 @@ func NewExportCommand(f *factory.Factory) *cobra.Command { return runExport(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runExport(opts) }, } diff --git a/pkg/cmd/registry/artifact/migrate/import.go b/pkg/cmd/registry/artifact/migrate/import.go index c2c8c48d7..97dd92b0a 100644 --- a/pkg/cmd/registry/artifact/migrate/import.go +++ b/pkg/cmd/registry/artifact/migrate/import.go @@ -5,11 +5,12 @@ import ( "os" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -19,22 +20,22 @@ type ImportOptions struct { file string registryID string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewImportCommand(f *factory.Factory) *cobra.Command { opts := &ImportOptions{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -52,17 +53,12 @@ func NewImportCommand(f *factory.Factory) *cobra.Command { return runImport(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runImport(opts) }, } diff --git a/pkg/cmd/registry/artifact/role/add/add.go b/pkg/cmd/registry/artifact/role/add/add.go index 879efd0d4..31ff66d9d 100644 --- a/pkg/cmd/registry/artifact/role/add/add.go +++ b/pkg/cmd/registry/artifact/role/add/add.go @@ -5,11 +5,12 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" @@ -25,23 +26,23 @@ type options struct { registryID string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewAddCommand creates a new command for creating new service registry access rules func NewAddCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -75,17 +76,12 @@ func NewAddCommand(f *factory.Factory) *cobra.Command { return runAdd(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runAdd(opts) }, } diff --git a/pkg/cmd/registry/artifact/role/list/list.go b/pkg/cmd/registry/artifact/role/list/list.go index 491933c7e..eabddef57 100644 --- a/pkg/cmd/registry/artifact/role/list/list.go +++ b/pkg/cmd/registry/artifact/role/list/list.go @@ -6,12 +6,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" @@ -28,23 +29,23 @@ type options struct { outputFormat string registryID string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewListCommand creates a new command for listing principal roles func NewListCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -62,17 +63,12 @@ func NewListCommand(f *factory.Factory) *cobra.Command { return runList(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runList(opts) }, @@ -112,15 +108,13 @@ func runList(opts *options) error { stdout := opts.IO.Out switch opts.outputFormat { - case dump.EmptyFormat: - rows := mapResponseItemsToRows(mappings) - dump.Table(opts.IO.Out, rows) + case dump.TableFormat: opts.Logger.Info("") + rows := mapResponseItemsToRows(mappings) + return dump.Formatted(opts.IO.Out, opts.outputFormat, rows) default: return dump.Formatted(stdout, opts.outputFormat, mappings) } - - return nil } func mapResponseItemsToRows(artifacts []registryinstanceclient.RoleMapping) []registryRow { diff --git a/pkg/cmd/registry/artifact/role/revoke/revoke.go b/pkg/cmd/registry/artifact/role/revoke/revoke.go index 375c2de8b..dad45e8c8 100644 --- a/pkg/cmd/registry/artifact/role/revoke/revoke.go +++ b/pkg/cmd/registry/artifact/role/revoke/revoke.go @@ -4,11 +4,12 @@ import ( "context" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" ) @@ -20,23 +21,23 @@ type options struct { principal string registryID string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewRevokeCommand creates command used to revoke access for the user func NewRevokeCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -63,17 +64,12 @@ func NewRevokeCommand(f *factory.Factory) *cobra.Command { return runRevoke(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runRevoke(opts) }, } diff --git a/pkg/cmd/registry/artifact/state/state.go b/pkg/cmd/registry/artifact/state/state.go index e6f194020..47e93243a 100644 --- a/pkg/cmd/registry/artifact/state/state.go +++ b/pkg/cmd/registry/artifact/state/state.go @@ -5,11 +5,12 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/artifact/util" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -24,23 +25,23 @@ type options struct { state string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + context context.Context + ServiceContext servicecontext.IContext } // NewSetMetadataCommand creates a new command for updating metadata for registry artifacts. func NewSetStateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -62,17 +63,12 @@ func NewSetStateCommand(f *factory.Factory) *cobra.Command { return runSet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runSet(opts) }, } diff --git a/pkg/cmd/registry/artifact/versions/versions.go b/pkg/cmd/registry/artifact/versions/versions.go index eaed51d83..0690340e3 100644 --- a/pkg/cmd/registry/artifact/versions/versions.go +++ b/pkg/cmd/registry/artifact/versions/versions.go @@ -5,13 +5,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" ) @@ -23,22 +24,22 @@ type options struct { registryID string - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Logger logging.Logger + Connection factory.ConnectionFunc + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewVersionsCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Logger: f.Logger, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Logger: f.Logger, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -57,17 +58,12 @@ func NewVersionsCommand(f *factory.Factory) *cobra.Command { return runGet(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("registry.no.service.selected.use.instance.id.flag") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runGet(opts) }, } diff --git a/pkg/cmd/registry/create/create.go b/pkg/cmd/registry/create/create.go index 2740c85ea..c2eb21ffa 100644 --- a/pkg/cmd/registry/create/create.go +++ b/pkg/cmd/registry/create/create.go @@ -12,8 +12,10 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/accountmgmtutil" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/remote" @@ -34,23 +36,25 @@ type options struct { interactive bool bypassTermsCheck bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Config config.IConfig + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // NewCreateCommand creates a new command for creating registry. func NewCreateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Config: f.Config, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -95,7 +99,12 @@ func NewCreateCommand(f *factory.Factory) *cobra.Command { } func runCreate(opts *options) error { - cfg, err := opts.Config.Load() + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -124,23 +133,9 @@ func runCreate(opts *options) error { } if !opts.bypassTermsCheck { - opts.Logger.Debug("Checking if terms and conditions have been accepted") - // the user must have accepted the terms and conditions from the provider - // before they can create a registry instance - err1, constants := remote.GetRemoteServiceConstants(opts.Context, opts.Logger) - if err1 != nil { + if err = checkTermsAccepted(opts, conn); err != nil { return err } - var termsAccepted bool - var termsURL string - termsAccepted, termsURL, err = accountmgmtutil.CheckTermsAccepted(opts.Context, constants.ServiceRegistry.Ams, conn) - if err != nil { - return err - } - if !termsAccepted && termsURL != "" { - opts.Logger.Info(opts.localizer.MustLocalize("service.info.termsCheck", localize.NewEntry("TermsURL", termsURL))) - return nil - } } opts.Logger.Info(opts.localizer.MustLocalize("registry.cmd.create.info.action", localize.NewEntry("Name", payload.GetName()))) @@ -161,19 +156,25 @@ func runCreate(opts *options) error { opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("registry.cmd.create.info.successMessage")) + compatibleEndpoints := registrycmdutil.GetCompatibilityEndpoints(response.GetRegistryUrl()) + + opts.Logger.Info(opts.localizer.MustLocalize( + "registry.common.log.message.compatibleAPIs", + localize.NewEntry("CoreRegistryAPI", compatibleEndpoints.CoreRegistry), + localize.NewEntry("SchemaRegistryAPI", compatibleEndpoints.SchemaRegistry), + localize.NewEntry("CncfSchemaRegistryAPI", compatibleEndpoints.CncfSchemaRegistry), + )) + if err = dump.Formatted(opts.IO.Out, opts.outputFormat, response); err != nil { return err } - registryConfig := &config.ServiceRegistryConfig{ - InstanceID: response.GetId(), - Name: response.GetName(), - } - if opts.autoUse { opts.Logger.Debug("Auto-use is set, updating the current instance") - cfg.Services.ServiceRegistry = registryConfig - if err := opts.Config.Save(cfg); err != nil { + currCtx.ServiceRegistryID = response.GetId() + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err := opts.ServiceContext.Save(svcContext); err != nil { return fmt.Errorf("%v: %w", opts.localizer.MustLocalize("registry.cmd.create.error.couldNotUse"), err) } } else { @@ -225,3 +226,25 @@ func promptPayload(opts *options) (payload *srsmgmtv1.RegistryCreate, err error) return payload, nil } + +func checkTermsAccepted(opts *options, conn connection.Connection) (err error) { + opts.Logger.Debug("Checking if terms and conditions have been accepted") + // the user must have accepted the terms and conditions from the provider + // before they can create a registry instance + err1, constants := remote.GetRemoteServiceConstants(opts.Context, opts.Logger) + if err1 != nil { + return err1 + } + var termsAccepted bool + var termsURL string + termsAccepted, termsURL, err = accountmgmtutil.CheckTermsAccepted(opts.Context, constants.ServiceRegistry.Ams, conn) + if err != nil { + return err + } + if !termsAccepted && termsURL != "" { + opts.Logger.Info(opts.localizer.MustLocalize("service.info.termsCheck", localize.NewEntry("TermsURL", termsURL))) + return nil + } + + return nil +} diff --git a/pkg/cmd/registry/delete/delete.go b/pkg/cmd/registry/delete/delete.go index 0d5a195af..0072ce7a1 100644 --- a/pkg/cmd/registry/delete/delete.go +++ b/pkg/cmd/registry/delete/delete.go @@ -6,12 +6,13 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" "github.com/spf13/cobra" @@ -24,22 +25,22 @@ type options struct { name string force bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewDeleteCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -61,17 +62,12 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { return runDelete(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - var serviceRegistryConfig *config.ServiceRegistryConfig - if cfg.Services.ServiceRegistry == serviceRegistryConfig || cfg.Services.ServiceRegistry.InstanceID == "" { - return opts.localizer.MustLocalizeError("registry.common.error.noServiceSelected") - } - - opts.id = cfg.Services.ServiceRegistry.InstanceID + opts.id = registryInstance.GetId() return runDelete(opts) }, @@ -85,7 +81,13 @@ func NewDeleteCommand(f *factory.Factory) *cobra.Command { } func runDelete(opts *options) error { - cfg, err := opts.Config.Load() + + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -142,17 +144,19 @@ func runDelete(opts *options) error { opts.Logger.Info(icon.SuccessPrefix(), opts.localizer.MustLocalize("registry.delete.log.info.deleteSuccess", localize.NewEntry("Name", registryName))) - currentContextRegistry := cfg.Services.ServiceRegistry + currentContextRegistry := currCtx.ServiceRegistryID // this is not the current cluster, our work here is done - if currentContextRegistry == nil || currentContextRegistry.InstanceID != opts.id { + if currentContextRegistry != opts.id { return nil } - // the service that was deleted is set as the user's current cluster - // since it was deleted it should be removed from the config - cfg.Services.ServiceRegistry = nil - err = opts.Config.Save(cfg) - if err != nil { + // the service that was deleted is set as the user's current instance + // since it was deleted it should be removed from the context + + currCtx.ServiceRegistryID = "" + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err := opts.ServiceContext.Save(svcContext); err != nil { return err } diff --git a/pkg/cmd/registry/describe/describe.go b/pkg/cmd/registry/describe/describe.go index e0b141a73..daf0389fa 100644 --- a/pkg/cmd/registry/describe/describe.go +++ b/pkg/cmd/registry/describe/describe.go @@ -3,15 +3,19 @@ package describe import ( "context" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" srsmgmtv1 "github.com/redhat-developer/app-services-sdk-go/registrymgmt/apiv1/client" + "github.com/spf13/cobra" ) @@ -20,22 +24,24 @@ type options struct { name string outputFormat string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + localizer localize.Localizer + logger logging.Logger + Context context.Context + ServiceContext servicecontext.IContext } // NewDescribeCommand describes a service instance, either by passing an `--id flag` -// or by using the service instance set in the config, if any +// or by using the service instance set in the current context, if any func NewDescribeCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + logger: f.Logger, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -58,17 +64,12 @@ func NewDescribeCommand(f *factory.Factory) *cobra.Command { return runDescribe(opts) } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - var registryConfig *config.ServiceRegistryConfig - if cfg.Services.ServiceRegistry == registryConfig || cfg.Services.ServiceRegistry.InstanceID == "" { - return opts.localizer.MustLocalizeError("registry.common.error.noServiceSelected") - } - - opts.id = cfg.Services.ServiceRegistry.InstanceID + opts.id = registryInstance.GetId() return runDescribe(opts) }, @@ -104,5 +105,18 @@ func runDescribe(opts *options) error { } } - return dump.Formatted(opts.IO.Out, opts.outputFormat, registry) + if err := dump.Formatted(opts.IO.Out, opts.outputFormat, registry); err != nil { + return err + } + + compatibleEndpoints := registrycmdutil.GetCompatibilityEndpoints(registry.GetRegistryUrl()) + + opts.logger.Info(opts.localizer.MustLocalize( + "registry.common.log.message.compatibleAPIs", + localize.NewEntry("CoreRegistryAPI", compatibleEndpoints.CoreRegistry), + localize.NewEntry("SchemaRegistryAPI", compatibleEndpoints.SchemaRegistry), + localize.NewEntry("CncfSchemaRegistryAPI", compatibleEndpoints.CncfSchemaRegistry), + )) + + return nil } diff --git a/pkg/cmd/registry/list/list.go b/pkg/cmd/registry/list/list.go index 0c200ba8e..292aaecdf 100644 --- a/pkg/cmd/registry/list/list.go +++ b/pkg/cmd/registry/list/list.go @@ -6,13 +6,14 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" srsmgmtv1 "github.com/redhat-developer/app-services-sdk-go/registrymgmt/apiv1/client" @@ -35,23 +36,23 @@ type options struct { limit int32 search string - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + ServiceContext servicecontext.IContext + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context } // NewListCommand creates a new command for listing service registries. func NewListCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -114,21 +115,29 @@ func runList(opts *options) error { } switch opts.outputFormat { - case dump.EmptyFormat: + case dump.TableFormat: var rows []RegistryRow - serviceConfig, _ := opts.Config.Load() - if serviceConfig != nil && serviceConfig.Services.ServiceRegistry != nil { - rows = mapResponseItemsToRows(&response.Items, serviceConfig.Services.ServiceRegistry.InstanceID) + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) + if err != nil { + return err + } + + if currCtx.ServiceRegistryID != "" { + rows = mapResponseItemsToRows(&response.Items, currCtx.ServiceRegistryID) } else { rows = mapResponseItemsToRows(&response.Items, "-") } - dump.Table(opts.IO.Out, rows) opts.Logger.Info("") + return dump.Formatted(opts.IO.Out, opts.outputFormat, rows) default: return dump.Formatted(opts.IO.Out, opts.outputFormat, response) } - return nil } func mapResponseItemsToRows(registries *[]srsmgmtv1.Registry, selectedId string) []RegistryRow { diff --git a/pkg/cmd/registry/registry.go b/pkg/cmd/registry/registry.go index 94e695c9f..103188bed 100644 --- a/pkg/cmd/registry/registry.go +++ b/pkg/cmd/registry/registry.go @@ -15,6 +15,7 @@ import ( "github.com/spf13/cobra" ) +// NewServiceRegistryCommand creates a new registry command. func NewServiceRegistryCommand(f *factory.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "service-registry", diff --git a/pkg/cmd/registry/registrycmdutil/registry_util.go b/pkg/cmd/registry/registrycmdutil/registry_util.go index 574b235be..510abca14 100644 --- a/pkg/cmd/registry/registrycmdutil/registry_util.go +++ b/pkg/cmd/registry/registrycmdutil/registry_util.go @@ -9,6 +9,12 @@ import ( var validNameRegexp = regexp.MustCompile(`^[a-z]([-a-z0-9]*[a-z0-9])?$`) +type compatibilityEndpoints struct { + CoreRegistry string `json:"coreRegistryAPI"` + SchemaRegistry string `json:"schemaRegistryCompatAPI"` + CncfSchemaRegistry string `json:"cncfSchemaRegistryAPI"` +} + // ValidateName validates the proposed name of a Kafka instance func ValidateName(val interface{}) error { name, ok := val.(string) @@ -29,3 +35,15 @@ func ValidateName(val interface{}) error { return errors.New("invalid service registry name: " + name) } + +// GetCompatibilityEndpoints returns the compatible API endpoints +func GetCompatibilityEndpoints(url string) *compatibilityEndpoints { + + endpoints := &compatibilityEndpoints{ + CoreRegistry: url + "/apis/registry/v2", + SchemaRegistry: url + "/apis/ccompat/v6", + CncfSchemaRegistry: url + "/apis/cncf/v0", + } + + return endpoints +} diff --git a/pkg/cmd/registry/rule/describe/describe.go b/pkg/cmd/registry/rule/describe/describe.go index 77546b840..9d81522f6 100644 --- a/pkg/cmd/registry/rule/describe/describe.go +++ b/pkg/cmd/registry/rule/describe/describe.go @@ -6,12 +6,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -19,12 +20,12 @@ import ( ) type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext ruleType string @@ -38,12 +39,12 @@ type options struct { func NewDescribeCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -63,17 +64,12 @@ func NewDescribeCommand(f *factory.Factory) *cobra.Command { return err } - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runDescribe(opts) }, diff --git a/pkg/cmd/registry/rule/disable/disable.go b/pkg/cmd/registry/rule/disable/disable.go index 36fc38db3..295c073c3 100644 --- a/pkg/cmd/registry/rule/disable/disable.go +++ b/pkg/cmd/registry/rule/disable/disable.go @@ -8,24 +8,25 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" "github.com/spf13/cobra" ) type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext ruleType string @@ -40,12 +41,12 @@ type options struct { func NewDisableCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -60,25 +61,12 @@ func NewDisableCommand(f *factory.Factory) *cobra.Command { return flagutil.RequiredWhenNonInteractiveError("yes") } - validator := rulecmdutil.Validator{ - Localizer: opts.localizer, - } - - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - if err = validator.ValidateRuleType(opts.ruleType); err != nil && opts.ruleType != "" { - return err - } - - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runDisable(opts) }, diff --git a/pkg/cmd/registry/rule/enable/enable.go b/pkg/cmd/registry/rule/enable/enable.go index 8bc222933..1c3ea7e1e 100644 --- a/pkg/cmd/registry/rule/enable/enable.go +++ b/pkg/cmd/registry/rule/enable/enable.go @@ -9,12 +9,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -22,12 +23,12 @@ import ( ) type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext ruleType string config string @@ -38,15 +39,16 @@ type options struct { } // NewEnableCommand creates a new command for enabling rule +// nolint:funlen func NewEnableCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -83,11 +85,6 @@ func NewEnableCommand(f *factory.Factory) *cobra.Command { return flagutil.RequiredWhenNonInteractiveError(missingFlags...) } - cfg, err := opts.Config.Load() - if err != nil { - return err - } - err = validator.ValidateRuleType(opts.ruleType) if err != nil { return err @@ -102,12 +99,12 @@ func NewEnableCommand(f *factory.Factory) *cobra.Command { ) } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err } - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runEnable(opts) }, diff --git a/pkg/cmd/registry/rule/list/list.go b/pkg/cmd/registry/rule/list/list.go index 78bff3741..7682ef3ed 100644 --- a/pkg/cmd/registry/rule/list/list.go +++ b/pkg/cmd/registry/rule/list/list.go @@ -7,15 +7,16 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" registryinstanceclient "github.com/redhat-developer/app-services-sdk-go/registryinstance/apiv1internal/client" ) @@ -39,12 +40,12 @@ type ruleRow struct { } type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext registryID string artifactID string @@ -55,12 +56,12 @@ type options struct { func NewListCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -71,17 +72,12 @@ func NewListCommand(f *factory.Factory) *cobra.Command { Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) (err error) { - cfg, err := opts.Config.Load() + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) if err != nil { return err } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") - } - - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runList(opts) }, diff --git a/pkg/cmd/registry/rule/update/update.go b/pkg/cmd/registry/rule/update/update.go index ffde79a67..3484ead11 100644 --- a/pkg/cmd/registry/rule/update/update.go +++ b/pkg/cmd/registry/rule/update/update.go @@ -7,12 +7,13 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/spf13/cobra" @@ -20,12 +21,12 @@ import ( ) type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext ruleType string config string @@ -39,12 +40,12 @@ type options struct { func NewUpdateCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - localizer: f.Localizer, - Context: f.Context, + IO: f.IOStreams, + Connection: f.Connection, + Logger: f.Logger, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -59,11 +60,6 @@ func NewUpdateCommand(f *factory.Factory) *cobra.Command { Localizer: opts.localizer, } - cfg, err := opts.Config.Load() - if err != nil { - return err - } - err = validator.ValidateRuleType(opts.ruleType) if err != nil { return err @@ -78,12 +74,12 @@ func NewUpdateCommand(f *factory.Factory) *cobra.Command { ) } - instanceID, ok := cfg.GetServiceRegistryIdOk() - if !ok { - return opts.localizer.MustLocalizeError("artifact.cmd.common.error.noServiceRegistrySelected") + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err } - opts.registryID = instanceID + opts.registryID = registryInstance.GetId() return runUpdate(opts) }, diff --git a/pkg/cmd/registry/use/use.go b/pkg/cmd/registry/use/use.go index 92409c250..614daefe2 100644 --- a/pkg/cmd/registry/use/use.go +++ b/pkg/cmd/registry/use/use.go @@ -9,7 +9,9 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" @@ -22,22 +24,24 @@ type options struct { name string interactive bool - IO *iostreams.IOStreams - Config config.IConfig - Connection factory.ConnectionFunc - Logger logging.Logger - localizer localize.Localizer - Context context.Context + IO *iostreams.IOStreams + Config config.IConfig + Connection factory.ConnectionFunc + Logger logging.Logger + localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } func NewUseCommand(f *factory.Factory) *cobra.Command { opts := &options{ - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - IO: f.IOStreams, - localizer: f.Localizer, - Context: f.Context, + Config: f.Config, + Connection: f.Connection, + Logger: f.Logger, + IO: f.IOStreams, + localizer: f.Localizer, + Context: f.Context, + ServiceContext: f.ServiceContext, } cmd := &cobra.Command{ @@ -81,7 +85,12 @@ func runUse(opts *options) error { } } - cfg, err := opts.Config.Load() + svcContext, err := opts.ServiceContext.Load() + if err != nil { + return err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, opts.localizer) if err != nil { return err } @@ -106,14 +115,11 @@ func runUse(opts *options) error { } } - registryConfig := &config.ServiceRegistryConfig{ - InstanceID: registry.GetId(), - Name: *registry.Name, - } - nameTmplEntry := localize.NewEntry("Name", registry.GetName()) - cfg.Services.ServiceRegistry = registryConfig - if err := opts.Config.Save(cfg); err != nil { + currCtx.ServiceRegistryID = registry.GetId() + svcContext.Contexts[svcContext.CurrentContext] = *currCtx + + if err := opts.ServiceContext.Save(svcContext); err != nil { saveErrMsg := opts.localizer.MustLocalize("registry.use.error.saveError", nameTmplEntry) return fmt.Errorf("%v: %w", saveErrMsg, err) } diff --git a/pkg/cmd/root/root.go b/pkg/cmd/root/root.go index d9fe8a3a3..ffa8f3831 100644 --- a/pkg/cmd/root/root.go +++ b/pkg/cmd/root/root.go @@ -3,7 +3,11 @@ package root import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/cluster" "github.com/redhat-developer/app-services-cli/pkg/cmd/completion" + + "github.com/redhat-developer/app-services-cli/pkg/cmd/connector" + "github.com/redhat-developer/app-services-cli/pkg/cmd/context" "github.com/redhat-developer/app-services-cli/pkg/cmd/docs" + "github.com/redhat-developer/app-services-cli/pkg/cmd/generate" "github.com/redhat-developer/app-services-cli/pkg/cmd/kafka" "github.com/redhat-developer/app-services-cli/pkg/cmd/login" "github.com/redhat-developer/app-services-cli/pkg/cmd/logout" @@ -11,6 +15,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/request" "github.com/redhat-developer/app-services-cli/pkg/cmd/serviceaccount" "github.com/redhat-developer/app-services-cli/pkg/cmd/status" + "github.com/redhat-developer/app-services-cli/pkg/cmd/token" cliversion "github.com/redhat-developer/app-services-cli/pkg/cmd/version" "github.com/redhat-developer/app-services-cli/pkg/cmd/whoami" "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" @@ -38,8 +43,6 @@ func NewRootCommand(f *factory.Factory, version string) *cobra.Command { cmd.Version = version - // pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - // Child commands cmd.AddCommand(login.NewLoginCmd(f)) cmd.AddCommand(logout.NewLogoutCommand(f)) @@ -47,14 +50,17 @@ func NewRootCommand(f *factory.Factory, version string) *cobra.Command { cmd.AddCommand(serviceaccount.NewServiceAccountCommand(f)) cmd.AddCommand(cluster.NewClusterCommand(f)) cmd.AddCommand(status.NewStatusCommand(f)) + cmd.AddCommand(generate.NewGenerateCommand(f)) cmd.AddCommand(completion.NewCompletionCommand(f)) cmd.AddCommand(whoami.NewWhoAmICmd(f)) cmd.AddCommand(cliversion.NewVersionCmd(f)) + cmd.AddCommand(token.NewAuthTokenCmd(f)) // Registry commands cmd.AddCommand(registry.NewServiceRegistryCommand(f)) - + cmd.AddCommand(connector.NewConnectorsCommand(f)) cmd.AddCommand(docs.NewDocsCmd(f)) cmd.AddCommand(request.NewCallCmd(f)) + cmd.AddCommand(context.NewContextCmd(f)) return cmd } diff --git a/pkg/cmd/serviceaccount/list/list.go b/pkg/cmd/serviceaccount/list/list.go index 0b0f21dce..278f22f48 100644 --- a/pkg/cmd/serviceaccount/list/list.go +++ b/pkg/cmd/serviceaccount/list/list.go @@ -88,14 +88,13 @@ func runList(opts *options) (err error) { outStream := opts.IO.Out switch opts.output { - case dump.EmptyFormat: + case dump.TableFormat: rows := mapResponseItemsToRows(serviceaccounts) - dump.Table(outStream, rows) + return dump.Formatted(outStream, opts.output, rows) default: return dump.Formatted(opts.IO.Out, opts.output, res) } - return nil } func mapResponseItemsToRows(svcAccts []kafkamgmtclient.ServiceAccountListItem) []svcAcctRow { diff --git a/pkg/cmd/status/status.go b/pkg/cmd/status/status.go index 9ba4aad33..84e827780 100644 --- a/pkg/cmd/status/status.go +++ b/pkg/cmd/status/status.go @@ -1,15 +1,11 @@ package status import ( - "context" - "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" - "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" - "github.com/redhat-developer/app-services-cli/pkg/core/logging" - "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/servicespec" @@ -17,44 +13,36 @@ import ( ) type options struct { - IO *iostreams.IOStreams - Config config.IConfig - Logger logging.Logger - Connection factory.ConnectionFunc - localizer localize.Localizer - Context context.Context + f *factory.Factory outputFormat string + name string services []string } func NewStatusCommand(f *factory.Factory) *cobra.Command { opts := &options{ - IO: f.IOStreams, - Config: f.Config, - Connection: f.Connection, - Logger: f.Logger, - services: servicespec.AllServiceLabels, - localizer: f.Localizer, - Context: f.Context, + f: f, } cmd := &cobra.Command{ Use: "status [args]", - Short: opts.localizer.MustLocalize("status.cmd.shortDescription"), - Long: opts.localizer.MustLocalize("status.cmd.longDescription"), - Example: opts.localizer.MustLocalize("status.cmd.example"), + Short: f.Localizer.MustLocalize("status.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("status.cmd.longDescription"), + Example: f.Localizer.MustLocalize("status.cmd.example"), ValidArgs: servicespec.AllServiceLabels, Args: cobra.RangeArgs(0, len(servicespec.AllServiceLabels)), RunE: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { for _, s := range args { if !flagutil.IsValidInput(s, servicespec.AllServiceLabels...) { - return opts.localizer.MustLocalizeError("status.error.args.error.unknownServiceError", localize.NewEntry("ServiceName", s)) + return f.Localizer.MustLocalizeError("status.error.args.error.unknownServiceError", localize.NewEntry("ServiceName", s)) } } opts.services = args + } else { + opts.services = servicespec.AllServiceLabels } validOutputFormats := flagutil.ValidOutputFormats @@ -66,7 +54,10 @@ func NewStatusCommand(f *factory.Factory) *cobra.Command { }, } - cmd.Flags().StringVarP(&opts.outputFormat, "output", "o", "", opts.localizer.MustLocalize("status.flag.output.description")) + flags := flagutil.NewFlagSet(cmd, f.Localizer) + + flags.StringVar(&opts.name, "name", "", f.Localizer.MustLocalize("context.common.flag.name")) + flags.AddOutput(&opts.outputFormat) flagutil.EnableOutputFlagCompletion(cmd) @@ -74,34 +65,50 @@ func NewStatusCommand(f *factory.Factory) *cobra.Command { } func runStatus(opts *options) error { - conn, err := opts.Connection(connection.DefaultConfigSkipMasAuth) + factory := opts.f + + if len(opts.services) > 0 { + opts.f.Logger.Debug(factory.Localizer.MustLocalize("status.log.debug.requestingStatusOfServices"), opts.services) + } + + svcContext, err := factory.ServiceContext.Load() if err != nil { return err } - if len(opts.services) > 0 { - opts.Logger.Debug(opts.localizer.MustLocalize("status.log.debug.requestingStatusOfServices"), opts.services) + var svcConfig *servicecontext.ServiceConfig + + if opts.name == "" { + svcConfig, err = contextutil.GetCurrentContext(svcContext, opts.f.Localizer) + if err != nil { + return err + } + } else { + svcConfig, err = contextutil.GetContext(svcContext, opts.f.Localizer, opts.name) + if err != nil { + return err + } } statusClient := newStatusClient(&clientConfig{ - config: opts.Config, - connection: conn, - Logger: opts.Logger, - localizer: opts.localizer, + f: factory, + serviceConfig: svcConfig, }) - status, ok, err := statusClient.BuildStatus(opts.Context, opts.services) + status, err := statusClient.BuildStatus(opts.services) if err != nil { return err } + status.Name = svcContext.CurrentContext + status.Location, _ = factory.ServiceContext.Location() - if !ok { - opts.Logger.Info("") - opts.Logger.Info(opts.localizer.MustLocalize("status.log.info.noStatusesAreUsed")) + if !status.hasStatus() { + factory.Logger.Info("") + factory.Logger.Info(factory.Localizer.MustLocalize("status.log.info.noStatusesAreUsed")) return nil } - stdout := opts.IO.Out + stdout := factory.IOStreams.Out if opts.outputFormat != "" { if err = dump.Formatted(stdout, opts.outputFormat, status); err != nil { return err diff --git a/pkg/cmd/status/statusBuilder.go b/pkg/cmd/status/statusBuilder.go index 4e098c0e5..2c3e5b8e7 100644 --- a/pkg/cmd/status/statusBuilder.go +++ b/pkg/cmd/status/statusBuilder.go @@ -1,23 +1,21 @@ package status import ( - "context" "fmt" "io" "reflect" "strings" "text/tabwriter" - "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" "github.com/redhat-developer/app-services-cli/pkg/shared/servicespec" "github.com/redhat-developer/app-services-cli/pkg/shared/svcstatus" + registrymgmtclient "github.com/redhat-developer/app-services-sdk-go/registrymgmt/apiv1/client" - kafkamgmtv1errors "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/error" + kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" - "github.com/redhat-developer/app-services-cli/pkg/core/config" - "github.com/redhat-developer/app-services-cli/pkg/core/localize" - "github.com/redhat-developer/app-services-cli/pkg/core/logging" - "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/openconfig/goyang/pkg/indent" ) @@ -25,10 +23,16 @@ import ( const tagTitle = "title" type serviceStatus struct { + Name string `json:"name,omitempty" title:"Service Context Name"` + Location string `json:"location,omitempty" title:"Context File Location"` Kafka *kafkaStatus `json:"kafka,omitempty" title:"Kafka"` Registry *registryStatus `json:"registry,omitempty" title:"Service Registry"` } +func (s serviceStatus) hasStatus() bool { + return s.Kafka != nil || s.Registry != nil +} + type kafkaStatus struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` @@ -45,82 +49,51 @@ type registryStatus struct { } type clientConfig struct { - config config.IConfig - Logger logging.Logger - connection connection.Connection - localizer localize.Localizer + f *factory.Factory + serviceConfig *servicecontext.ServiceConfig } type statusClient struct { - config config.IConfig - Logger logging.Logger - conn connection.Connection - localizer localize.Localizer + f *factory.Factory + serviceConfig *servicecontext.ServiceConfig } // newStatusClient returns a new client to fetch service statuses // and build it into a service status config object func newStatusClient(cfg *clientConfig) *statusClient { return &statusClient{ - config: cfg.config, - Logger: cfg.Logger, - conn: cfg.connection, - localizer: cfg.localizer, + f: cfg.f, + serviceConfig: cfg.serviceConfig, } } -// BuildStatus gets the status of all services currently set in the user config -func (c *statusClient) BuildStatus(ctx context.Context, services []string) (status *serviceStatus, ok bool, err error) { - cfg, err := c.config.Load() - if err != nil { - return nil, false, err - } +// BuildStatus gets the status of all services currently set in the service context +func (c *statusClient) BuildStatus(services []string) (status *serviceStatus, err error) { + factory := c.f status = &serviceStatus{} - if stringInSlice(servicespec.KafkaServiceName, services) { - if instanceID, exists := cfg.GetKafkaIdOk(); exists { - // nolint:govet - kafkaStatus, err := c.getKafkaStatus(ctx, instanceID) - if err != nil { - if kafkamgmtv1errors.IsAPIError(err, kafkamgmtv1errors.ERROR_7) { - err = kafkautil.NotFoundByIDError(instanceID) - c.Logger.Error(err) - c.Logger.Info(c.localizer.MustLocalize("status.log.info.rhoasKafkaUse")) - } - } else { - status.Kafka = kafkaStatus - ok = true - } - } else { - c.Logger.Debug("No Kafka instance is currently used, skipping status check") + if stringInSlice(servicespec.KafkaServiceName, services) && c.serviceConfig.KafkaID != "" { + kafkaResponse, err1 := contextutil.GetKafkaForServiceConfig(c.serviceConfig, factory) + if err1 != nil { + return status, err1 } + kafkaStatus := c.getKafkaStatus(kafkaResponse) + status.Kafka = kafkaStatus } - if stringInSlice(servicespec.ServiceRegistryServiceName, services) { - registryCfg := cfg.Services.ServiceRegistry - if registryCfg != nil && registryCfg.InstanceID != "" { - // nolint:govet - registry, newErr := c.getRegistryStatus(ctx, registryCfg.InstanceID) - if newErr != nil { - return status, ok, err - } - status.Registry = registry - ok = true - } else { - c.Logger.Debug("No service registry is currently used, skipping status check") + if stringInSlice(servicespec.ServiceRegistryServiceName, services) && c.serviceConfig.ServiceRegistryID != "" { + registryResponse, err1 := contextutil.GetRegistryForServiceConfig(c.serviceConfig, factory) + if err1 != nil { + return status, err1 } + registry := c.getRegistryStatus(registryResponse) + status.Registry = registry } - - return status, ok, err + return status, err } -func (c *statusClient) getKafkaStatus(ctx context.Context, id string) (status *kafkaStatus, err error) { - kafkaResponse, _, err := c.conn.API().KafkaMgmt().GetKafkaById(ctx, id).Execute() - if err != nil { - return nil, err - } - +func (c *statusClient) getKafkaStatus(kafkaResponse *kafkamgmtclient.KafkaRequest) (status *kafkaStatus) { status = &kafkaStatus{ ID: kafkaResponse.GetId(), Name: kafkaResponse.GetName(), @@ -132,15 +105,10 @@ func (c *statusClient) getKafkaStatus(ctx context.Context, id string) (status *k status.FailedReason = kafkaResponse.GetFailedReason() } - return status, err + return status } -func (c *statusClient) getRegistryStatus(ctx context.Context, id string) (status *registryStatus, err error) { - registry, _, err := c.conn.API().ServiceRegistryMgmt().GetRegistry(ctx, id).Execute() - if err != nil { - return nil, err - } - +func (c *statusClient) getRegistryStatus(registry *registrymgmtclient.Registry) (status *registryStatus) { status = ®istryStatus{ ID: registry.GetId(), Name: registry.GetName(), @@ -148,7 +116,7 @@ func (c *statusClient) getRegistryStatus(ctx context.Context, id string) (status Status: string(registry.GetStatus()), } - return status, err + return status } // Print prints the status information of all set services @@ -159,9 +127,13 @@ func Print(w io.Writer, status *serviceStatus) { for i := 0; i < indirectVal.NumField(); i++ { fieldType := indirectVal.Type().Field(i) fieldVal := indirectVal.Field(i) + title := getTitle(&fieldType) + + if fieldVal.Kind() == reflect.String { + fmt.Fprintf(w, "%v:\t%v\n", title, fieldVal) + } - if !fieldVal.IsNil() { - title := getTitle(&fieldType) + if fieldVal.Kind() == reflect.Ptr && !fieldVal.IsNil() { fmt.Fprintln(w, "") printServiceStatus(w, title, fieldVal) } diff --git a/pkg/cmd/token/token.go b/pkg/cmd/token/token.go new file mode 100644 index 000000000..548c114a9 --- /dev/null +++ b/pkg/cmd/token/token.go @@ -0,0 +1,64 @@ +package token + +import ( + "fmt" + + "github.com/redhat-developer/app-services-cli/pkg/core/config" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +type options struct { + Config config.IConfig + Connection factory.ConnectionFunc + IO *iostreams.IOStreams + Logger logging.Logger + localizer localize.Localizer +} + +func NewAuthTokenCmd(f *factory.Factory) *cobra.Command { + opts := &options{ + Config: f.Config, + Connection: f.Connection, + IO: f.IOStreams, + Logger: f.Logger, + localizer: f.Localizer, + } + + cmd := &cobra.Command{ + Use: "authtoken", + Short: f.Localizer.MustLocalize("token.cmd.shortDescription"), + Long: f.Localizer.MustLocalize("token.cmd.longDescription"), + Example: f.Localizer.MustLocalize("token.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return runCmd(opts) + }, + } + + return cmd +} + +func runCmd(opts *options) (err error) { + cfg, err := opts.Config.Load() + if err != nil { + return err + } + + _, err = opts.Connection(connection.DefaultConfigSkipMasAuth) + if err != nil { + return err + } + + if cfg.AccessToken != "" { + fmt.Fprintln(opts.IO.Out, cfg.AccessToken) + } else { + opts.Logger.Info(opts.localizer.MustLocalize("token.log.info.tokenUnavailable")) + } + + return nil +} diff --git a/pkg/core/cmdutil/flagutil/flagset.go b/pkg/core/cmdutil/flagutil/flagset.go index 0997a8355..cfd5a8162 100644 --- a/pkg/core/cmdutil/flagutil/flagset.go +++ b/pkg/core/cmdutil/flagutil/flagset.go @@ -11,7 +11,8 @@ import ( ) var ( - ValidOutputFormats = []string{dump.JSONFormat, dump.YAMLFormat, dump.YMLFormat} + ValidOutputFormats = []string{dump.JSONFormat, dump.YAMLFormat, dump.YMLFormat, dump.EmptyFormat} + ValidListOutputFormats = append(ValidOutputFormats, dump.TableFormat) ) type FlagSet struct { @@ -29,20 +30,38 @@ func NewFlagSet(cmd *cobra.Command, localizer localize.Localizer) *FlagSet { } } -// AddOutput adds an output flag to the command +// AddOutput executes AddOutputFormatted with required inputs func (fs *FlagSet) AddOutput(output *string) { + fs.AddOutputFormatted(output, false, nil) +} + +// AddOutputFormatted adds an output flag to the command +func (fs *FlagSet) AddOutputFormatted(output *string, isTable bool, format *string) { flagName := "output" + selectedFormat := dump.JSONFormat + + if format != nil && *format != "" { + selectedFormat = *format + + } + + suggestions := ValidOutputFormats + + if isTable { + suggestions = ValidListOutputFormats + } + fs.StringVarP( output, flagName, "o", - dump.EmptyFormat, - FlagDescription(fs.localizer, "flag.common.output.description", ValidOutputFormats...), + selectedFormat, + FlagDescription(fs.localizer, "flag.common.output.description", suggestions...), ) _ = fs.cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return ValidOutputFormats, cobra.ShellCompDirectiveNoSpace + return suggestions, cobra.ShellCompDirectiveNoSpace }) } @@ -116,3 +135,25 @@ func WithFlagOptions(cmd *cobra.Command, flagName string) *FlagOptions { type FlagOptions struct { Required func() error } + +// ValidateOutput checks if value v is a valid value for --output +func ValidateOutput(v string) error { + isValid := IsValidInput(v, ValidOutputFormats...) + + if isValid { + return nil + } + + return InvalidValueError("output", v, ValidOutputFormats...) +} + +// ValidateOutputForTable checks if value v is a valid value for --output adding table +func ValidateOutputForTable(v string) error { + isValid := IsValidInput(v, ValidListOutputFormats...) + + if isValid { + return nil + } + + return InvalidValueError("output", v, ValidListOutputFormats...) +} diff --git a/pkg/core/cmdutil/flagutil/validation.go b/pkg/core/cmdutil/flagutil/validation.go deleted file mode 100644 index f92a53dba..000000000 --- a/pkg/core/cmdutil/flagutil/validation.go +++ /dev/null @@ -1,12 +0,0 @@ -package flagutil - -// ValidateOutput checks if value v is a valid value for --output -func ValidateOutput(v string) error { - isValid := IsValidInput(v, ValidOutputFormats...) - - if isValid { - return nil - } - - return InvalidValueError("output", v, ValidOutputFormats...) -} diff --git a/pkg/core/cmdutil/selfupdate.go b/pkg/core/cmdutil/selfupdate.go new file mode 100644 index 000000000..ae97a773e --- /dev/null +++ b/pkg/core/cmdutil/selfupdate.go @@ -0,0 +1,87 @@ +package cmdutil + +import ( + "time" + + "github.com/AlecAivazis/survey/v2" + "github.com/blang/semver" + "github.com/redhat-developer/app-services-cli/internal/build" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/wtrocki/go-github-selfupdate/selfupdate" +) + +// DoSelfUpdate checks for updates and prompts the user to update if there is a newer version available +func DoSelfUpdate(f *factory.Factory) (bool, error) { + version := build.Version + slug := build.RepositoryOwner + "/" + build.RepositoryName + + v := semver.MustParse(version) + versionToUpdate, found, err := selfupdate.DefaultUpdater().DetectLatest(slug) + if err != nil { + return false, err + } + if found && versionToUpdate.Version.Equals(v) { + // latest version is the same as current version. It means current binary is up to date. + f.Logger.Debug("Current binary is the latest version", version) + return false, nil + } + + promptConfirmName := &survey.Confirm{ + Message: f.Localizer.MustLocalize("common.selfupdate.confirm", localize.NewEntry("Version", versionToUpdate.Version.String())), + } + + var confirmUpdate bool + err = survey.AskOne(promptConfirmName, &confirmUpdate) + if err != nil { + return false, err + } + + if !confirmUpdate { + return false, nil + } + + latest, err := selfupdate.UpdateSelf(v, slug) + if err != nil { + return false, err + } + + f.Logger.Info(f.Localizer.MustLocalize("common.selfupdate.success", localize.NewEntry("Version", latest.Version))) + return true, err + +} + +// DoSelfUpdate checks for updates once per day and prompts the user to update if there is a newer version available +func DoSelfUpdateOnceADay(f *factory.Factory) (bool, error) { + if !f.IOStreams.CanPrompt() { + // Do not prompt if we are not in interactive mode + return false, nil + } + + if build.IsDevBuild() { + return false, nil + } + + cfg, err := f.Config.Load() + + logger := f.Logger + + if err != nil { + return false, err + } + logger.Debug("Checking for updates. Last check was done:", cfg.LastUpdated) + + if cfg.LastUpdated < time.Now().AddDate(0, 0, -1).UnixMilli() { + updated, err := DoSelfUpdate(f) + if err != nil { + return false, err + } + cfg.LastUpdated = time.Now().UnixMilli() + err = f.Config.Save(cfg) + if err != nil { + return false, err + } + return updated, nil + } + return false, nil +} diff --git a/pkg/core/config/type.go b/pkg/core/config/type.go index 9f3aaff00..ce143b628 100644 --- a/pkg/core/config/type.go +++ b/pkg/core/config/type.go @@ -24,12 +24,13 @@ type Config struct { Insecure bool `json:"insecure,omitempty" doc:"Enables insecure communication with the server. This disables verification of TLS certificates and host names."` Scopes []string `json:"scopes,omitempty" doc:"OpenID scope. If this option is used it will replace completely the default scopes. Can be repeated multiple times to specify multiple scopes."` Telemetry string `json:"telemetry,omitempty" doc:"Flag used to enable telemetry for user."` + LastUpdated int64 `json:"last_updated,omitempty" doc:"Timestamp of the last update cli"` } // ServiceConfigMap is a map of configs for the application services type ServiceConfigMap struct { - Kafka *KafkaConfig `json:"kafka"` - ServiceRegistry *ServiceRegistryConfig `json:"serviceregistry"` + Kafka *KafkaConfig `json:"kafka,omitempty"` + ServiceRegistry *ServiceRegistryConfig `json:"serviceregistry,omitempty"` } // KafkaConfig is the config for the Kafka service diff --git a/pkg/core/ioutil/dump/dump.go b/pkg/core/ioutil/dump/dump.go index ee68985b1..8d38484a6 100644 --- a/pkg/core/ioutil/dump/dump.go +++ b/pkg/core/ioutil/dump/dump.go @@ -21,7 +21,8 @@ const ( JSONFormat = "json" YAMLFormat = "yaml" YMLFormat = "yml" - EmptyFormat = "" + TableFormat = "table" + EmptyFormat = "none" ) // JSON dumps the given data to the given stream so that it looks pretty. If the data is a valid @@ -153,11 +154,18 @@ func Formatted(writer io.Writer, format string, data interface{}) error { return err } return YAML(writer, data) - default: + case EmptyFormat: + return nil + case JSONFormat: data, err := json.Marshal(data) if err != nil { return err } return JSON(writer, data) + case TableFormat: + Table(writer, data) + return nil + default: + return nil } } diff --git a/pkg/core/localize/locales/en/cmd/artifact.en.toml b/pkg/core/localize/locales/en/cmd/artifact.en.toml index 88fa5783c..1dcc925fa 100644 --- a/pkg/core/localize/locales/en/cmd/artifact.en.toml +++ b/pkg/core/localize/locales/en/cmd/artifact.en.toml @@ -112,9 +112,6 @@ one = 'Output format (json, yaml, yml)' [artifact.common.message.no.artifact.available.for.group.and.registry] one = 'No artifacts found for {{.Group}} group and registry ID {{.Registry}}' -[artifact.common.message.reading.file] -one = 'Reading file content from standard input' - [artifact.common.message.deleteAllArtifactsInGroup] one = 'Artifact was not specified. Command will delete all artifacts in the group' diff --git a/pkg/core/localize/locales/en/cmd/common.en.toml b/pkg/core/localize/locales/en/cmd/common.en.toml index d2b649953..17184bd79 100644 --- a/pkg/core/localize/locales/en/cmd/common.en.toml +++ b/pkg/core/localize/locales/en/cmd/common.en.toml @@ -10,4 +10,7 @@ one = 'Starting interactive prompt' one = 'invalid page number {{.Page}}, minimum value is -1' [common.validation.limit.error.invalid.minValue] -one = 'invalid value for limit {{.Limit}}, minimum value is -1' \ No newline at end of file +one = 'invalid value for limit {{.Limit}}, minimum value is -1' + +[common.message.reading.file] +one = 'Reading file content from standard input' \ No newline at end of file diff --git a/pkg/core/localize/locales/en/cmd/connectors.toml b/pkg/core/localize/locales/en/cmd/connectors.toml new file mode 100644 index 000000000..369b74fa0 --- /dev/null +++ b/pkg/core/localize/locales/en/cmd/connectors.toml @@ -0,0 +1,264 @@ +[connector.cluster.addonParams.cmd.shortDescription] +one = 'Get Addon parameters' + +[connector.cluster.addonParams.cmd.longDescription] +one = 'Get Addon parameters' + + +[connector.cluster.addonParams.cmd.example] +one = ''' +## Get addon parameters +rhoas connector cluster addon-parameters +''' + +[connector.cluster.cmd.shortDescription] +one = 'Connectors cluster commands' + +[connector.cluster.cmd.longDescription] +one = 'Connectors cluster commands' + +[connector.cluster.cmd.example] +one = ''' +## Create connectors cluster +rhoas connector cluster create --name=test +''' + +[connector.cluster.create.cmd.shortDescription] +one = 'Create connectors cluster' + +[connector.cluster.create.cmd.longDescription] +one = 'Create connectors cluster' + +[connector.cluster.create.cmd.example] +one = ''' +## Create connectors cluster +rhoas connector cluster create --name=test +''' + +[connector.cluster.create.info.success] +one = 'Successfully created cluster for connectors' + +[connector.cluster.delete.cmd.shortDescription] +one = 'Delete connectors cluster' + +[connector.cluster.delete.cmd.longDescription] +one = 'Delete connectors cluster' + +[connector.cluster.delete.cmd.example] +one = ''' +## Delete connectors cluster +rhoas connector cluster delete --id=c980124otd37bufiemj0 +''' + +[connector.cluster.delete.id.flag.description] +one = 'Id of connectors cluster to delete' + +[connector.cluster.create.flag.name.description] +one = 'Name of the cluster to create' + +[connector.cluster.delete.info.success] +one = 'Successfully deleted cluster' + +[connector.cluster.delete.confirmDialog.message] +one = 'Are you sure you want to delete the connector cluster with id "{{.ID}}"?' + +[connector.cluster.list.cmd.shortDescription] +one = 'List connectors clusters' + +[connector.cluster.list.cmd.longDescription] +one = 'List connectors clusters' + +[connector.cluster.list.cmd.example] +one = ''' +## List connectors clusters +rhoas connector cluster list +''' + +[connector.common.id.flag] +one = 'Unique identifier' + +[connector.common.list.flag.page] +one = 'Page number' + +[connector.common.list.flag.limit] +one = 'Page limit' + +[connector.common.log.info.noResults] +one = 'No results returned from current command' + +[connector.common.validation.namespace.error.invalidChars] +one = 'invalid name for namespace "{{.Name}}"' + +[connector.cmd.shortDescription] +one = 'Connectors commands' + +[connector.cmd.longDescription] +one = 'Connectors commands' + + +[connector.cmd.example] +one = ''' +## List connectors +rhoas connector list +''' + +[connector.create.cmd.shortDescription] +one = 'Create connector' + +[connector.create.cmd.longDescription] +one = 'Create connector' + +[connector.create.cmd.example] +one = ''' +## Create connector +rhoas connector create --file=myconnector.json + +## Create connector from stdin +cat myconnector.json | rhoas connector create +''' + +[connector.create.info.success] +one = 'Successfully created connector' + +[connector.update.cmd.shortDescription] +one = 'Update connector' + +[connector.update.cmd.longDescription] +one = 'Update connector' + +[connector.update.cmd.example] +one = ''' +## Update connector +rhoas connector update --id=my-connector --file=myconnector.json + +## Update connector from stdin +cat myconnector.json | rhoas connector update +''' + +[connector.update.info.success] +one = 'Successfully updated connector' + +[connector.file.flag.description] +one = 'Location of the connector json file describing the connector' + +[connector.delete.cmd.shortDescription] +one = 'Delete connector' + +[connector.delete.cmd.longDescription] +one = 'Delete connector' + +[connector.delete.cmd.example] +one = ''' +# Delete connector +rhoas connector delete --id=c9b71ucotd37bufoamkg +''' + +[connector.delete.flag.id.description] +one = 'Id of the connector to delete' + +[connector.delete.info.success] +one = 'Successfully deleted connector' + + +[connector.delete.confirmDialog.message] +one = 'Are you sure you want to delete the connector with id "{{.ID}}"?' + +[connector.describe.cmd.shortDescription] +one = 'Get connector details' + +[connector.describe.cmd.longDescription] +one = 'Get connector details' + +[connector.describe.cmd.example] +one = ''' +## Get connector details +rhoas connector describe --id=c980124otd37bufiemj0 +''' + +[connector.common.flag.id.description] +one = 'Id of the connector' + +[connector.describe.info.success] +one = 'Connector details returned successfully' + +[connector.list.cmd.shortDescription] +one = 'List connectors' + +[connector.list.cmd.longDescription] +one = 'List connectors' + +[connector.list.cmd.example] +one = ''' +## List connectors +rhoas connector list +''' + +[connector.namespace.cmd.shortDescription] +one = 'Connector namespace commands' + +[connector.namespace.cmd.longDescription] +one = 'Commands to manage namespaces for connectors' + +[connector.namespace.cmd.example] +one = ''' +# List namespaces in the connector instance +$ rhoas connector namespace list + +# Create a namespace in connector instance +$ rhoas connector name space create --name "my-namespace" +''' + +[connector.namespace.create.flag.name.description] +one = 'Name of the namespace' + +[connector.namespace.create.flag.eval.description] +one = 'Create an evaluation namespace' + +[connector.namespace.list.cmd.shortDescription] +one = 'Get connector namespaces' + +[connector.namespace.list.cmd.longDescription] +one = 'Get connector namespaces' + +[connector.namespace.list.cmd.example] +one = ''' +## Get connector namespaces list +rhoas connector namespace list +''' + +[connector.namespace.create.cmd.shortDescription] +one = 'Create a connector namespace' + +[connector.namespace.create.cmd.longDescription] +one = 'Create a connector namespace' + +[connector.namespace.create.cmd.example] +one = ''' +# Create a connector namespace +rhoas connector namespace create --name "my-namespace" + +# Create an evaluation namespace +rhoas connector namespace create --name "my-namespace" --eval +''' + +[connector.namespace.create.info.success] +one = 'Successfully created namespace' + + +[connector.namespace.delete.cmd.shortDescription] +one = 'Delete a connector namespace' + +[connector.namespace.delete.cmd.longDescription] +one = 'Delete a connector namespace' + +[connector.namespace.delete.cmd.example] +one = ''' +# Delete a connector namespace +rhoas connector namespace delete --id jdhdhdhmmf +''' + +[connector.namespace.delete.info.success] +one = 'Successfully deleted namespace' + +[connector.namespace.delete.confirmDialog.message] +one = 'Are you sure you want to delete the connector namespace with id "{{.ID}}"?' \ No newline at end of file diff --git a/pkg/core/localize/locales/en/cmd/context.en.toml b/pkg/core/localize/locales/en/cmd/context.en.toml new file mode 100644 index 000000000..e57eb3b3c --- /dev/null +++ b/pkg/core/localize/locales/en/cmd/context.en.toml @@ -0,0 +1,266 @@ +[context.cmd.shortDescription] +one='Group, share and manage your rhoas services' + +[context.cmd.longDescription] +one=''' +Group your service instances into reusable contexts. +Context can be used when running other rhoas commands or to generate service configuration. + +A service context is a group of application service instances and their service identifiers. By using service contexts, you can group together application service instances that you want to use together. + +After creating a service context, you can share it with other developers so that they can use the same group of application service instances. + +You can also use the service context to automatically generate configuration files that you need to use those application service instances in other development platforms and tools. For example, the service context can generate the following types of configurations: + +- Standard environment variables for use in local development and tooling +- Java properties files that can be used in Quarkus, Apache Kafka, and so on +- Service binding configuration and service connections for the RHOAS Operator +- Configuration for Helm Charts and Kubernetes + +The service context is defined in a JSON file (`contexts.json`), and stored locally on your computer. To find the location of this file, use the "rhoas context status" command. + +Note: To specify a custom location for the `contexts.json` file, set the $RHOAS_CONTEXT environment variable to the location you want to use. If you set $RHOAS_CONTEXT to "./rhoas.json", service contexts will be loaded from the current directory. +''' + +[context.cmd.example] +one=''' +# Set the current context +$ rhoas context use --name qa + +# List contexts +$ rhoas context list + +# Create a context to represent a group of development services +$ rhoas context create --name dev-env +''' + +[context.use.cmd] + +[context.use.cmd.shortDescription] +one='Set the current context' + +[context.use.cmd.longDescription] +one=''' +Select a service context to be used as the current context. + +When you set the context to be used, it is set as the current context for all service-based rhoas commands. +''' + +[context.use.cmd.example] +one=''' +# Set the current context +$ rhoas context use --name dev +''' + +[context.use.successMessage] +one='Current context set to "{{.Name}}"' + +[context.status.cmd] + +[context.status.cmd.longDescription] +one = ''' +View the status of your application services. This command shows the status of each of the application services instances in the service context. + +To view the status of a specific application service, use "rhoas context status [service]". + +Note: You can change the current instance for an application service with the "rhoas [service] use” command. +''' + +[context.status.cmd.example] +one=''' +# View the status of all application services in the current service context +$ rhoas context status + +# View the status of all application services in a specific service context +$ rhoas context status --name my-context + +# View the status of the Kafka instance set in the current service context +$ rhoas context status kafka + +# View the status of your services in JSON format +$ rhoas context status -o json +''' + +[context.useKafka.cmd.example] +description = 'Examples of how to use the command' +one = ''' +# Select a Kafka instance by name to be set in the current context +$ rhoas context use-kafka --name=my-kafka + +# Select a Kafka instance by ID to be set in the current context +$ rhoas context use-kafka --id=1iSY6RQ3JKI8Q0OTmjQFd3ocFRg +''' + +[context.useRegistry.cmd.example] +one = ''' +# Select a Service Registry instance by name to be set in the current context +rhoas context use-service-registry --name my-service-registry + +# Select a Service Registry instance by ID to be set in the current context +rhoas context use-service-registry --id 1iSY6RQ3JKI8Q0OTmjQFd3ocFRg +''' + +[context.list.cmd] + +[context.list.cmd.shortDescription] +one='List service contexts' + +[context.list.cmd.longDescription] +one=''' +List all service contexts. This command lists each service context, and indicates the context that is currently being used. + +To view the details of a service context, use the "rhoas context status" command. +''' + +[context.list.cmd.example] +one=''' +# List contexts +$ rhoas context list +''' + +[context.list.log.info.noContexts] +one=''' +No service contexts exist. + +Run the following command to create a service context: + + $ rhoas context create +''' + +[context.create.cmd] + +[context.create.cmd.shortDescription] +one='Create a service context' + +[context.create.cmd.longDescription] +one=''' +Create a service context and assign associated service identifiers. + +A service context is a group of application service instances and their configuration details. By creating a service context, you can group together application service instances that you want to use together. + +After creating the service context, add application service instances to it by using the "rhoas context use-[service]" commands. +''' + +[context.create.cmd.example] +one=''' +# Create context +$ rhoas context create --name dev +''' + +[context.create.input.name.message] +one='Name:' + +[context.create.input.name.help] +one='Unique name of service context' + +[context.create.log.successMessage] +one=''' +Context created successfully + +Run the following commands to set service instances in the created context: + + $ rhoas context use-[service] +''' + +[context.create.log.alreadyExists] +one='Context with name "{{.Name}}" already exists' + +[context.delete.cmd] + +[context.delete.cmd.shortDescription] +one='Permanently delete a service context.' + +[context.delete.cmd.longDescription] +one='Delete a service context.' + +[context.delete.cmd.example] +one=''' +# Delete the currently-selected service context +$ rhoas context delete + +# Delete a service context by name +$ rhoas context delete --name dev +''' + +[context.delete.log.warning.currentUnset] +one='Warning: Your current service context has been removed, use "rhoas context use" to select a different context' + +[context.delete.log.successMessage] +one='Context deleted successfully' + +[context.generate.cmd] + +[context.generate.cmd.shortDescription] +one='Generate configurations for the service context' + +[context.generate.cmd.longDescription] +one=''' +Generate configuration files to enable the application service instances in the service context to connect with other platforms and tools. + +This command generates a JSON configuration file that you can use to connect application service instances to other development platforms and tools. +''' + +[context.generate.cmd.example] +one=''' +# Generate configurations for the current service context in JSON format +$ rhoas context generate-config --type json +''' + +[context.generate.flag.type] +one='Type of configuration file to be generated' + +[context.generate.log.info.noSevices] +one='No services available to generate configurations' + +[context.generate.log.info.credentialsSaved] +one='Configurations successfully saved' + +[context.common.flag.name] +one='Name of the context' + +[context.common.error.noRegistryID] +one=''' +The context doesn't have a Service Registry ID. +Use the "rhoas context use-service-registry" command to select a Service Registry instance for your context +''' + +[context.common.error.noKafkaID] +one=''' +The context doesn't have a Kafka instance ID. +Use the "rhoas context use-kafka" command to select a Kafka instance for your context +''' + +[context.common.error.registry.notFound] +one=''' +Service registry instance in your context doesn't exist. +Your instance might have been removed. +You can update your context by creating a new instance or by using the "rhoas context use-service-registry" command +''' + +[context.common.error.kafka.notFound] +one=''' +Kafka instance doesn't exist, you must set a valid Kafka instance ID by using the "rhoas context use-kafka" command +''' + +[context.common.error.context.notFound] +one=''' +context with name "{{.Name}}" does not exist + +Run "rhoas context list" to view available contexts +''' + +[context.common.error.notSet] +one=''' +The command you have been trying to execute requires a service context. +Current context has not been set. +Run either "rhoas context use" or "rhoas context create" to set a context. +For example: + + $ rhoas context use --name default +''' + +[context.common.validation.name.error.required] +one = 'context name is required' + +[context.common.validation.name.error.invalidChars] +one = 'invalid context name "{{.Name}}"; only lowercase letters (a-z), numbers, and "-" are accepted' diff --git a/pkg/core/localize/locales/en/cmd/generate_config.en.toml b/pkg/core/localize/locales/en/cmd/generate_config.en.toml new file mode 100644 index 000000000..6075cb466 --- /dev/null +++ b/pkg/core/localize/locales/en/cmd/generate_config.en.toml @@ -0,0 +1,20 @@ +[generate.cmd.shortDescription] +one='Generate configurations for the service context' + +[generate.cmd.longDescription] +one='Generate configuration files for the service context to connect with to be used with various tools and platforms' + +[generate.cmd.example] +one=''' +## Generate configurations for the current service context in json format +$ rhoas generate-config --type json +''' + +[generate.flag.type] +one='Type of configuration file to be generated' + +[generate.log.info.noSevices] +one='No services available to generate configurations' + +[generate.log.info.credentialsSaved] +one='Configurations successfully saved' \ No newline at end of file diff --git a/pkg/core/localize/locales/en/cmd/kafka.en.toml b/pkg/core/localize/locales/en/cmd/kafka.en.toml index 08f87cbaa..bafce1a2c 100644 --- a/pkg/core/localize/locales/en/cmd/kafka.en.toml +++ b/pkg/core/localize/locales/en/cmd/kafka.en.toml @@ -319,6 +319,9 @@ one = 'Kafka instance "{{.Name}}" already exists' [kafka.create.error.oneinstance] one = 'maximum number of allowed instances reached. Please review all instances that your user has access to and delete one or more instances before creating a new one.' +[kafka.create.error.notsupported] +one = 'Kafka instance creation is not supported for this cloud provider region and account' + [kafka.create.error.temporary.unavailable] one = 'unable to create new Kafka instance at this time in specified cloud provider and region. Please try again later or choose another region.' @@ -780,10 +783,10 @@ You can select a Kafka instance by name or ID. [kafka.use.cmd.example] description = 'Examples of how to use the command' one = ''' -# Select a Kafka instance to be the current instance +# Select a Kafka instance by name to be set in the current context $ rhoas kafka use --name=my-kafka -# Select a Kafka instance to be the current instance +# Select a Kafka instance by ID to be set in the current context $ rhoas kafka use --id=1iSY6RQ3JKI8Q0OTmjQFd3ocFRg ''' diff --git a/pkg/core/localize/locales/en/cmd/main.en.toml b/pkg/core/localize/locales/en/cmd/main.en.toml index 3dcff3dbf..bad8361d9 100644 --- a/pkg/core/localize/locales/en/cmd/main.en.toml +++ b/pkg/core/localize/locales/en/cmd/main.en.toml @@ -1,2 +1,8 @@ [main.config.error] -one = 'Error when initializing configuration: "{{.Error}}"' \ No newline at end of file +one = 'Error when initializing configuration: "{{.Error}}"' + +[main.context.error] +one = 'Error when initializing service contexts: "{{.Error}}"' + +[main.update.error] +one = 'Error when updating cli: "{{.Error}}"' diff --git a/pkg/core/localize/locales/en/cmd/registry_crud.en.toml b/pkg/core/localize/locales/en/cmd/registry_crud.en.toml index 2f627d40f..7882f8de2 100644 --- a/pkg/core/localize/locales/en/cmd/registry_crud.en.toml +++ b/pkg/core/localize/locales/en/cmd/registry_crud.en.toml @@ -211,6 +211,17 @@ one = 'Filtering Service Registry instances with the query "{{.Search}}".' description = 'Info message when no Registry instances were found' one = 'No Service Registry instances were found.' +[registry.common.log.message.compatibleAPIs] +one=''' +You can connect to the Service Registry instance using following options: + - For Apicurio Service Registry API: + {{.CoreRegistryAPI}} + - For tools supporting Confluent Schema Registry API: + {{.SchemaRegistryAPI}} + - For CNCF Schema Registry API: + {{.CncfSchemaRegistryAPI}} +''' + [registry.use.flag.id] description = 'Description for the --id flag' one = 'Unique ID of the Service Registry instance you want to set as the current instance' diff --git a/pkg/core/localize/locales/en/cmd/status.en.toml b/pkg/core/localize/locales/en/cmd/status.en.toml index 988af65f5..5ee6feec2 100644 --- a/pkg/core/localize/locales/en/cmd/status.en.toml +++ b/pkg/core/localize/locales/en/cmd/status.en.toml @@ -1,9 +1,9 @@ [status.cmd.shortDescription] -one = 'View the status of your application services' +one = 'View the status of application services in a service context' [status.cmd.longDescription] one = ''' -View the status of your application services. This command shows the status of the current instance for each of your application services. +View the status of your application services. This command shows the status of each of your application services instances that belong to a service context. To view the status of a specific application service, use "rhoas status [service]". @@ -12,10 +12,10 @@ Note: You can change the current instance for an application service with the "r [status.cmd.example] one = ''' -# View the status of all application services +# View the status of all application services in the current service context $ rhoas status -# View the status of the current Kafka instance +# View the status of all application services in a specific service context $ rhoas status kafka # View the status of your services in JSON format @@ -25,20 +25,11 @@ $ rhoas status -o json [status.error.args.error.unknownServiceError] one = 'unknown service "{{.ServiceName}}"' -[status.flag.output.description] -one = 'Format in which to display the status of your services (choose from: "json", "yml", "yaml")' - [status.log.debug.requestingStatusOfServices] one = 'Requesting status of the following services:' [status.log.info.noStatusesAreUsed] -one = 'No services are currently being used. To set a service in context, run "rhoas [service] use [args]".' +one = 'No services set in context. To set a service in context, run "rhoas context use-[service] [args]".' [status.log.debug.noKafkaSelected] one = 'No Kafka instance is currently used, skipping status check' - -[status.log.info.selectAnotherKafka] -one = 'Run rhoas kafka use --id=1iSY6RQ3JKI8Q0OTmjQFd3ocFRg to use another Kafka instance.' - -[status.log.info.rhoasKafkaUse] -one = 'Run "rhoas kafka use" to use another Kafka instance.' \ No newline at end of file diff --git a/pkg/core/localize/locales/en/cmd/token.en.toml b/pkg/core/localize/locales/en/cmd/token.en.toml new file mode 100644 index 000000000..30783c9a6 --- /dev/null +++ b/pkg/core/localize/locales/en/cmd/token.en.toml @@ -0,0 +1,22 @@ +[token.cmd.shortDescription] +description = "Short description for command" +one = "Output the current token" + +[token.cmd.longDescription] +description = "Long description for command" +one = ''' +View the authentication token of the current user that can be used to +make general API requests against api.openshift.com APIs. + +This command outputs the token for the user currently logged in. +''' + +[token.cmd.example] +description = 'Examples of how to use the command' +one = ''' +# Returns header with token used for authorization +$ echo Authorization: BEARER ${rhoas authtoken} +''' + +[token.log.info.tokenUnavailable] +one = 'Token unavailable' diff --git a/pkg/core/localize/locales/en/common.en.toml b/pkg/core/localize/locales/en/common.en.toml index 2c52984fe..5a5709101 100644 --- a/pkg/core/localize/locales/en/common.en.toml +++ b/pkg/core/localize/locales/en/common.en.toml @@ -21,3 +21,14 @@ You can also disable telemetry by setting the "RHOAS_TELEMETRY" environment vari [common.telemetry.question] one = 'Do you agree to send anonymous data' + +[common.selfupdate.confirm] +one = ''' +RHOAS CLI can be updated to {{.Version}}. +Do you want to update now? + +NOTE: You might need to run command as root to update RHOAS CLI binary. +''' + +[common.selfupdate.success] +one = 'RHOAS CLI updated to version {{.Version}}' \ No newline at end of file diff --git a/pkg/core/servicecontext/file.go b/pkg/core/servicecontext/file.go new file mode 100644 index 000000000..6725318f8 --- /dev/null +++ b/pkg/core/servicecontext/file.go @@ -0,0 +1,134 @@ +package servicecontext + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +// NewFile creates a new context type +func NewFile() IContext { + cfg := &File{} + + return cfg +} + +// File is a type which describes a context file +type File struct{} + +const errorFormat = "%v: %w" + +const ContextEnvName = "RHOAS_CONTEXT" + +// Load loads the profiles from the context file. If the context file doesn't exist +// it will return an empty context object. +func (c *File) Load() (*Context, error) { + file, err := c.Location() + if err != nil { + return nil, err + } + + _, err = os.Stat(file) + if os.IsNotExist(err) { + return nil, err + } + if err != nil { + return nil, fmt.Errorf(errorFormat, "unable to check if context file exists", err) + } + // #nosec G304 + data, err := ioutil.ReadFile(file) + if err != nil { + return nil, fmt.Errorf(errorFormat, "unable to read context file", err) + } + var ctx Context + err = json.Unmarshal(data, &ctx) + if err != nil { + return nil, fmt.Errorf(errorFormat, "unable to parse contexts", err) + } + return &ctx, nil +} + +// Save saves the given profiles to the context file. +func (c *File) Save(cfg *Context) error { + file, err := c.Location() + if err != nil { + return err + } + data, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return fmt.Errorf("%v: %w", "unable to marshal context", err) + } + rhoasCfgDir, err := DefaultDir() + if err != nil { + return err + } + if _, err = os.Stat(rhoasCfgDir); os.IsNotExist(err) { + err = os.Mkdir(rhoasCfgDir, 0o700) + if err != nil { + return err + } + } + err = ioutil.WriteFile(file, data, 0o600) + if err != nil { + return fmt.Errorf(errorFormat, "unable to save context", err) + } + return nil +} + +// Remove removes the context file. +func (c *File) Remove() error { + file, err := c.Location() + if err != nil { + return err + } + _, err = os.Stat(file) + if os.IsNotExist(err) { + return nil + } + err = os.Remove(file) + if err != nil { + return err + } + return nil +} + +// Location gets the path to the context file +func (c *File) Location() (path string, err error) { + + if rhoasContext := os.Getenv(ContextEnvName); rhoasContext != "" { + + _, err := os.Stat(rhoasContext) + if os.IsNotExist(err) { + return "", fmt.Errorf("Custom file path '%s' provided doesn't exist", rhoasContext) + } + + path = rhoasContext + } else { + rhoasCtxDir, err := DefaultDir() + if err != nil { + return "", err + } + path = filepath.Join(rhoasCtxDir, "contexts.json") + if err != nil { + return "", err + } + } + return path, nil +} + +// Checks if context has custom location +func HasCustomLocation() bool { + rhoasContext := os.Getenv(ContextEnvName) + return rhoasContext != "" +} + +// DefaultDir returns the default parent directory of the context file +func DefaultDir() (string, error) { + userCtxDir, err := os.UserConfigDir() + if err != nil { + return "", err + } + return filepath.Join(userCtxDir, "rhoas"), nil +} diff --git a/pkg/core/servicecontext/type.go b/pkg/core/servicecontext/type.go new file mode 100644 index 000000000..fe318b371 --- /dev/null +++ b/pkg/core/servicecontext/type.go @@ -0,0 +1,21 @@ +package servicecontext + +// Context is a type which describes the properties of context file +type Context struct { + Contexts map[string]ServiceConfig `json:"contexts,omitempty"` + CurrentContext string `json:"current_context"` +} + +// ServiceConfig is a map of identifiers for the application services +type ServiceConfig struct { + KafkaID string `json:"kafkaID"` + ServiceRegistryID string `json:"serviceregistryID"` +} + +// IContext is an interface which describes functions for context file +type IContext interface { + Load() (*Context, error) + Save(*Context) error + Remove() error + Location() (string, error) +} diff --git a/pkg/shared/cluster/services/kafka.go b/pkg/shared/cluster/services/kafka.go index 2f3f811bb..b717894be 100644 --- a/pkg/shared/cluster/services/kafka.go +++ b/pkg/shared/cluster/services/kafka.go @@ -6,6 +6,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/services/resources" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" "github.com/redhat-developer/app-services-cli/pkg/shared/servicespec" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,7 +20,12 @@ type KafkaService struct { func (s KafkaService) BuildServiceDetails(serviceName string, namespace string, ignoreContext bool) (*ServiceDetails, error) { cliOpts := s.CommandEnvironment - cfg, err := cliOpts.Config.Load() + svcContext, err := cliOpts.ServiceContext.Load() + if err != nil { + return nil, err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, cliOpts.Localizer) if err != nil { return nil, err } @@ -28,7 +34,7 @@ func (s KafkaService) BuildServiceDetails(serviceName string, namespace string, var serviceId string if serviceName == "" { - if cfg.Services.Kafka == nil || ignoreContext { + if currCtx.KafkaID == "" || ignoreContext { // nolint selectedService, err := kafkautil.InteractiveSelect(cliOpts.Context, cliOpts.Connection, cliOpts.Logger, cliOpts.Localizer) if err != nil { @@ -40,7 +46,7 @@ func (s KafkaService) BuildServiceDetails(serviceName string, namespace string, serviceId = selectedService.GetId() serviceName = selectedService.GetName() } else { - serviceId = cfg.Services.Kafka.ClusterID + serviceId = currCtx.KafkaID selectedService, _, err := kafkautil.GetKafkaByID(cliOpts.Context, api.KafkaMgmt(), serviceId) if err != nil { return nil, err diff --git a/pkg/shared/cluster/services/service-registry.go b/pkg/shared/cluster/services/service-registry.go index 40a1fc8e4..274cd7595 100644 --- a/pkg/shared/cluster/services/service-registry.go +++ b/pkg/shared/cluster/services/service-registry.go @@ -6,6 +6,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/kubeclient" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/services/resources" "github.com/redhat-developer/app-services-cli/pkg/shared/cluster/v1alpha" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/serviceregistryutil" "github.com/redhat-developer/app-services-cli/pkg/shared/servicespec" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,7 +20,12 @@ type RegistryService struct { func (s RegistryService) BuildServiceDetails(serviceName string, namespace string, ignoreContext bool) (*ServiceDetails, error) { cliOpts := s.CommandEnvironment - cfg, err := cliOpts.Config.Load() + svcContext, err := cliOpts.ServiceContext.Load() + if err != nil { + return nil, err + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, cliOpts.Localizer) if err != nil { return nil, err } @@ -28,7 +34,7 @@ func (s RegistryService) BuildServiceDetails(serviceName string, namespace strin var serviceId string if serviceName == "" { - if cfg.Services.ServiceRegistry == nil || ignoreContext { + if currCtx.ServiceRegistryID == "" || ignoreContext { // nolint selectedService, err := serviceregistryutil.InteractiveSelect(cliOpts.Context, cliOpts.Connection, cliOpts.Logger) if err != nil { @@ -40,7 +46,7 @@ func (s RegistryService) BuildServiceDetails(serviceName string, namespace strin serviceId = selectedService.GetId() serviceName = selectedService.GetName() } else { - serviceId = cfg.Services.ServiceRegistry.InstanceID + serviceId = currCtx.ServiceRegistryID selectedService, _, err := serviceregistryutil.GetServiceRegistryByID( cliOpts.Context, api.ServiceRegistryMgmt(), serviceId) if err != nil { diff --git a/pkg/shared/cluster/v1alpha/cluster.go b/pkg/shared/cluster/v1alpha/cluster.go index 77a91e4f8..a911ee1c5 100644 --- a/pkg/shared/cluster/v1alpha/cluster.go +++ b/pkg/shared/cluster/v1alpha/cluster.go @@ -3,21 +3,21 @@ package v1alpha import ( "context" - "github.com/redhat-developer/app-services-cli/pkg/core/config" "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" ) // CommandEnvironment provides number of abstractions provided by CLI type CommandEnvironment struct { - Connection connection.Connection - Config config.IConfig - Logger logging.Logger - IO *iostreams.IOStreams - Localizer localize.Localizer - Context context.Context + Connection connection.Connection + Logger logging.Logger + IO *iostreams.IOStreams + Localizer localize.Localizer + Context context.Context + ServiceContext servicecontext.IContext } // ConnectOperationOptions contains input flags for connect method diff --git a/pkg/shared/connection/api/api.go b/pkg/shared/connection/api/api.go index 8e3e497e4..66a45efd9 100644 --- a/pkg/shared/connection/api/api.go +++ b/pkg/shared/connection/api/api.go @@ -1,8 +1,14 @@ package api import ( + "net/http" + "net/url" + "github.com/redhat-developer/app-services-cli/pkg/api/generic" "github.com/redhat-developer/app-services-cli/pkg/api/rbac" + "github.com/redhat-developer/app-services-cli/pkg/core/logging" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" + amsclient "github.com/redhat-developer/app-services-sdk-go/accountmgmt/apiv1/client" kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" @@ -13,10 +19,22 @@ import ( type API interface { KafkaMgmt() kafkamgmtclient.DefaultApi ServiceRegistryMgmt() registrymgmtclient.RegistriesApi + ConnectorsMgmt() connectormgmtclient.APIClient ServiceAccountMgmt() kafkamgmtclient.SecurityApi KafkaAdmin(instanceID string) (*kafkainstanceclient.APIClient, *kafkamgmtclient.KafkaRequest, error) ServiceRegistryInstance(instanceID string) (*registryinstanceclient.APIClient, *registrymgmtclient.Registry, error) AccountMgmt() amsclient.AppServicesApi RBAC() rbac.RbacAPI GenericAPI() generic.GenericAPI + GetConfig() Config +} + +type Config struct { + AccessToken string + MasAccessToken string + ApiURL *url.URL + ConsoleURL *url.URL + UserAgent string + HTTPClient *http.Client + Logger logging.Logger } diff --git a/pkg/shared/connection/api/defaultapi/default_client.go b/pkg/shared/connection/api/defaultapi/default_client.go index ae9ecc9b0..ec1e040a9 100644 --- a/pkg/shared/connection/api/defaultapi/default_client.go +++ b/pkg/shared/connection/api/defaultapi/default_client.go @@ -7,6 +7,8 @@ import ( "net/http" "net/url" + connectormgmt "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1" + connectormgmtclient "github.com/redhat-developer/app-services-sdk-go/connectormgmt/apiv1/client" kafkamgmt "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1" "github.com/redhat-developer/app-services-cli/pkg/shared/kafkautil" @@ -14,7 +16,6 @@ import ( "github.com/redhat-developer/app-services-cli/internal/build" "github.com/redhat-developer/app-services-cli/pkg/api/generic" "github.com/redhat-developer/app-services-cli/pkg/api/rbac" - "github.com/redhat-developer/app-services-cli/pkg/core/logging" "github.com/redhat-developer/app-services-cli/pkg/shared/connection/api" "github.com/redhat-developer/app-services-cli/pkg/shared/svcstatus" amsclient "github.com/redhat-developer/app-services-sdk-go/accountmgmt/apiv1/client" @@ -31,41 +32,23 @@ import ( // defaultAPI is a type which defines a number of API creator functions type defaultAPI struct { - AccessToken string - MasAccessToken string - ApiURL *url.URL - ConsoleURL *url.URL - UserAgent string - HTTPClient *http.Client - Logger logging.Logger -} - -type Config struct { - AccessToken string - MasAccessToken string - ApiURL *url.URL - ConsoleURL *url.URL - UserAgent string - HTTPClient *http.Client - Logger logging.Logger + api.Config } // New creates a new default API client wrapper -func New(cfg *Config) api.API { +func New(cfg *api.Config) api.API { return &defaultAPI{ - AccessToken: cfg.AccessToken, - MasAccessToken: cfg.MasAccessToken, - ApiURL: cfg.ApiURL, - ConsoleURL: cfg.ConsoleURL, - UserAgent: cfg.UserAgent, - HTTPClient: cfg.HTTPClient, - Logger: cfg.Logger, + Config: *cfg, } } +func (a *defaultAPI) GetConfig() api.Config { + return a.Config +} + // KafkaMgmt returns a new Kafka Management API client instance func (a *defaultAPI) KafkaMgmt() kafkamgmtclient.DefaultApi { - tc := a.createOAuthTransport(a.AccessToken) + tc := a.CreateOAuthTransport(a.AccessToken) client := kafkamgmt.NewAPIClient(&kafkamgmt.Config{ BaseURL: a.ApiURL.String(), Debug: a.Logger.DebugEnabled(), @@ -78,7 +61,7 @@ func (a *defaultAPI) KafkaMgmt() kafkamgmtclient.DefaultApi { // ServiceRegistryMgmt return a new Service Registry Management API client instance func (a *defaultAPI) ServiceRegistryMgmt() registrymgmtclient.RegistriesApi { - tc := a.createOAuthTransport(a.AccessToken) + tc := a.CreateOAuthTransport(a.AccessToken) client := registrymgmt.NewAPIClient(®istrymgmt.Config{ BaseURL: a.ApiURL.String(), Debug: a.Logger.DebugEnabled(), @@ -91,7 +74,7 @@ func (a *defaultAPI) ServiceRegistryMgmt() registrymgmtclient.RegistriesApi { // ServiceAccountMgmt return a new Service Account Management API client instance func (a *defaultAPI) ServiceAccountMgmt() kafkamgmtclient.SecurityApi { - tc := a.createOAuthTransport(a.AccessToken) + tc := a.CreateOAuthTransport(a.AccessToken) client := kafkamgmt.NewAPIClient(&kafkamgmt.Config{ BaseURL: a.ApiURL.String(), Debug: a.Logger.DebugEnabled(), @@ -164,7 +147,7 @@ func (a *defaultAPI) KafkaAdmin(instanceID string) (*kafkainstanceclient.APIClie client := kafkainstance.NewAPIClient(&kafkainstance.Config{ BaseURL: apiURL.String(), Debug: a.Logger.DebugEnabled(), - HTTPClient: a.createOAuthTransport(a.MasAccessToken), + HTTPClient: a.CreateOAuthTransport(a.MasAccessToken), UserAgent: a.UserAgent, }) @@ -225,7 +208,7 @@ func (a *defaultAPI) ServiceRegistryInstance(instanceID string) (*registryinstan client := registryinstance.NewAPIClient(®istryinstance.Config{ BaseURL: baseURL, Debug: a.Logger.DebugEnabled(), - HTTPClient: a.createOAuthTransport(a.MasAccessToken), + HTTPClient: a.CreateOAuthTransport(a.MasAccessToken), UserAgent: build.DefaultUserAgentPrefix + build.Version, }) @@ -233,7 +216,7 @@ func (a *defaultAPI) ServiceRegistryInstance(instanceID string) (*registryinstan } func (a *defaultAPI) GenericAPI() generic.GenericAPI { - tc := a.createOAuthTransport(a.AccessToken) + tc := a.CreateOAuthTransport(a.AccessToken) client := generic.NewGenericAPIClient(&generic.Config{ BaseURL: a.ApiURL.String(), Debug: a.Logger.DebugEnabled(), @@ -243,6 +226,17 @@ func (a *defaultAPI) GenericAPI() generic.GenericAPI { return client } +func (a *defaultAPI) ConnectorsMgmt() connectormgmtclient.APIClient { + tc := a.CreateOAuthTransport(a.AccessToken) + client := connectormgmt.NewAPIClient(&connectormgmt.Config{ + BaseURL: a.ApiURL.String(), + Debug: a.Logger.DebugEnabled(), + HTTPClient: tc, + }) + + return *client +} + // AccountMgmt returns a new Account Management API client instance func (a *defaultAPI) AccountMgmt() amsclient.AppServicesApi { cfg := amsclient.NewConfiguration() @@ -251,7 +245,7 @@ func (a *defaultAPI) AccountMgmt() amsclient.AppServicesApi { cfg.Host = a.ApiURL.Host cfg.UserAgent = a.UserAgent - cfg.HTTPClient = a.createOAuthTransport(a.AccessToken) + cfg.HTTPClient = a.CreateOAuthTransport(a.AccessToken) apiClient := amsclient.NewAPIClient(cfg) @@ -262,7 +256,7 @@ func (a *defaultAPI) AccountMgmt() amsclient.AppServicesApi { func (a *defaultAPI) RBAC() rbac.RbacAPI { rbacAPI := rbac.RbacAPI{ PrincipalAPI: func() rbac.PrincipalAPI { - cl := a.createOAuthTransport(a.AccessToken) + cl := a.CreateOAuthTransport(a.AccessToken) cfg := rbac.Config{ HTTPClient: cl, Debug: a.Logger.DebugEnabled(), @@ -275,7 +269,7 @@ func (a *defaultAPI) RBAC() rbac.RbacAPI { } // wraps the HTTP client with an OAuth2 Transport layer to provide automatic token refreshing -func (a *defaultAPI) createOAuthTransport(accessToken string) *http.Client { +func (a *defaultAPI) CreateOAuthTransport(accessToken string) *http.Client { ts := oauth2.StaticTokenSource( &oauth2.Token{ AccessToken: accessToken, diff --git a/pkg/shared/connection/kcconnection/keycloak_connection.go b/pkg/shared/connection/kcconnection/keycloak_connection.go index bf065b75d..13f6ccd2c 100644 --- a/pkg/shared/connection/kcconnection/keycloak_connection.go +++ b/pkg/shared/connection/kcconnection/keycloak_connection.go @@ -142,7 +142,7 @@ func (c *Connection) Logout(ctx context.Context) (err error) { // API Creates a new API type which is a single type for multiple APIs func (c *Connection) API() api.API { - apiClient := defaultapi.New(&defaultapi.Config{ + apiClient := defaultapi.New(&api.Config{ HTTPClient: c.defaultHTTPClient, UserAgent: build.DefaultUserAgentPrefix + build.Version, MasAccessToken: c.MASToken.AccessToken, diff --git a/pkg/shared/contextutil/util.go b/pkg/shared/contextutil/util.go new file mode 100644 index 000000000..41d05cc59 --- /dev/null +++ b/pkg/shared/contextutil/util.go @@ -0,0 +1,111 @@ +package contextutil + +import ( + "context" + + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + srsmgmtv1errors "github.com/redhat-developer/app-services-sdk-go/registrymgmt/apiv1/error" + + registrymgmtclient "github.com/redhat-developer/app-services-sdk-go/registrymgmt/apiv1/client" + + kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" + kafkamgmtv1errors "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/error" +) + +// GetContext returns the services associated with the context +func GetContext(svcContext *servicecontext.Context, localizer localize.Localizer, ctxName string) (*servicecontext.ServiceConfig, error) { + + ctx, ok := svcContext.Contexts[ctxName] + if !ok { + return nil, localizer.MustLocalizeError("context.common.error.context.notFound", localize.NewEntry("Name", svcContext.CurrentContext)) + } + + return &ctx, nil + +} + +// GetCurrentContext returns the name of the currently selected context +func GetCurrentContext(svcContext *servicecontext.Context, localizer localize.Localizer) (*servicecontext.ServiceConfig, error) { + + if svcContext.CurrentContext == "" { + return nil, localizer.MustLocalizeError("context.common.error.notSet") + } + + currCtx, ok := svcContext.Contexts[svcContext.CurrentContext] + if !ok { + return nil, localizer.MustLocalizeError("context.common.error.context.notFound", localize.NewEntry("Name", svcContext.CurrentContext)) + } + + return &currCtx, nil +} + +// GetCurrentKafkaInstance returns the Kafka instance set in the currently selected context +func GetCurrentKafkaInstance(f *factory.Factory) (*kafkamgmtclient.KafkaRequest, error) { + + svcContext, err := f.ServiceContext.Load() + if err != nil { + return nil, err + } + + currCtx, err := GetCurrentContext(svcContext, f.Localizer) + if err != nil { + return nil, err + } + + return GetKafkaForServiceConfig(currCtx, f) +} + +func GetKafkaForServiceConfig(currCtx *servicecontext.ServiceConfig, f *factory.Factory) (*kafkamgmtclient.KafkaRequest, error) { + conn, err := f.Connection(connection.DefaultConfigRequireMasAuth) + if err != nil { + return nil, err + } + if currCtx.KafkaID == "" { + return nil, f.Localizer.MustLocalizeError("context.common.error.noKafkaID") + } + + kafkaInstance, _, err := conn.API().KafkaMgmt().GetKafkaById(context.Background(), currCtx.KafkaID).Execute() + if kafkamgmtv1errors.IsAPIError(err, kafkamgmtv1errors.ERROR_7) { + return nil, f.Localizer.MustLocalizeError("context.common.error.kafka.notFound") + } + + return &kafkaInstance, err +} + +// GetCurrentRegistryInstance returns the Service Registry instance set in the currently selected context +func GetCurrentRegistryInstance(f *factory.Factory) (*registrymgmtclient.Registry, error) { + + svcContext, err := f.ServiceContext.Load() + if err != nil { + return nil, err + } + + currCtx, err := GetCurrentContext(svcContext, f.Localizer) + if err != nil { + return nil, err + } + + return GetRegistryForServiceConfig(currCtx, f) + +} + +func GetRegistryForServiceConfig(currCtx *servicecontext.ServiceConfig, f *factory.Factory) (*registrymgmtclient.Registry, error) { + conn, err := f.Connection(connection.DefaultConfigRequireMasAuth) + if err != nil { + return nil, err + } + + if currCtx.ServiceRegistryID == "" { + return nil, f.Localizer.MustLocalizeError("context.common.error.noRegistryID") + } + + registryInstance, _, err := conn.API().ServiceRegistryMgmt().GetRegistry(context.Background(), currCtx.ServiceRegistryID).Execute() + if srsmgmtv1errors.IsAPIError(err, srsmgmtv1errors.ERROR_2) { + return nil, f.Localizer.MustLocalizeError("context.common.error.registry.notFound") + } + + return ®istryInstance, err +} diff --git a/pkg/shared/factory/defaultfactory/default.go b/pkg/shared/factory/defaultfactory/default.go index d8c2706b5..adbb843f0 100644 --- a/pkg/shared/factory/defaultfactory/default.go +++ b/pkg/shared/factory/defaultfactory/default.go @@ -9,6 +9,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" "github.com/redhat-developer/app-services-cli/pkg/shared/connection" "github.com/redhat-developer/app-services-cli/pkg/shared/connection/kcconnection" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" @@ -27,6 +28,7 @@ func New(localizer localize.Localizer) *factory.Factory { var logger logging.Logger var conn connection.Connection cfgFile := config.NewFile() + ctxFile := servicecontext.NewFile() loggerBuilder := logging.NewStdLoggerBuilder() loggerBuilder = loggerBuilder.Streams(io.Out, io.ErrOut) @@ -108,11 +110,12 @@ func New(localizer localize.Localizer) *factory.Factory { } return &factory.Factory{ - IOStreams: io, - Config: cfgFile, - Connection: connectionFunc, - Logger: logger, - Localizer: localizer, - Context: ctx, + IOStreams: io, + Config: cfgFile, + Connection: connectionFunc, + Logger: logger, + Localizer: localizer, + Context: ctx, + ServiceContext: ctxFile, } } diff --git a/pkg/shared/factory/factory.go b/pkg/shared/factory/factory.go index b24af0c54..8ef023dc2 100644 --- a/pkg/shared/factory/factory.go +++ b/pkg/shared/factory/factory.go @@ -4,6 +4,8 @@ import ( "context" "github.com/redhat-developer/app-services-cli/pkg/core/config" + "github.com/redhat-developer/app-services-cli/pkg/core/servicecontext" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/iostreams" "github.com/redhat-developer/app-services-cli/pkg/core/localize" "github.com/redhat-developer/app-services-cli/pkg/core/logging" @@ -25,6 +27,8 @@ type Factory struct { Localizer localize.Localizer // Context returns the default context for the application Context context.Context + // ServiceContext returns the identifiers for currently selected services for the context + ServiceContext servicecontext.IContext } type ConnectionFunc func(cfg *connection.Config) (connection.Connection, error) diff --git a/pkg/shared/kafkautil/util.go b/pkg/shared/kafkautil/util.go index a731e9903..5183fc378 100644 --- a/pkg/shared/kafkautil/util.go +++ b/pkg/shared/kafkautil/util.go @@ -2,6 +2,7 @@ package kafkautil import ( "github.com/redhat-developer/app-services-cli/pkg/shared/connection" + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" "github.com/redhat-developer/app-services-cli/pkg/shared/factory" kafkamgmtclient "github.com/redhat-developer/app-services-sdk-go/kafkamgmt/apiv1/client" "github.com/spf13/cobra" @@ -147,13 +148,18 @@ func FilterValidTopicNameArgs(f *factory.Factory, toComplete string) (validNames validNames = []string{} directive = cobra.ShellCompDirectiveNoSpace - cfg, err := f.Config.Load() + svcContext, err := f.ServiceContext.Load() if err != nil { return validNames, directive } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { + currCtx, err := contextutil.GetCurrentContext(svcContext, f.Localizer) + if err != nil { + return validNames, directive + } + + instanceID := currCtx.KafkaID + if instanceID == "" { return validNames, directive } @@ -189,13 +195,18 @@ func FilterValidConsumerGroupIDs(f *factory.Factory, toComplete string) (validID validIDs = []string{} directive = cobra.ShellCompDirectiveNoSpace - cfg, err := f.Config.Load() + svcContext, err := f.ServiceContext.Load() + if err != nil { + return validIDs, directive + } + + currCtx, err := contextutil.GetCurrentContext(svcContext, f.Localizer) if err != nil { return validIDs, directive } - instanceID, ok := cfg.GetKafkaIdOk() - if !ok { + instanceID := currCtx.KafkaID + if instanceID == "" { return validIDs, directive } diff --git a/scripts/messages.tmp.sh b/scripts/messages.tmp.sh new file mode 100644 index 000000000..f47c756cd --- /dev/null +++ b/scripts/messages.tmp.sh @@ -0,0 +1,7 @@ + +cat **/*.go | grep MustLocalize > messages.toml + +## Grep +## From .*MustLocalize\(" to [ +## From .*MustLocalizeError\(" to [ +## From ".* to ] \n one = '' \n \ No newline at end of file