From 60b40bb9c431f199a1cae4b726ce6b35baa58a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emirhan=20Durmu=C5=9F?= Date: Tue, 24 Feb 2026 12:55:15 +0300 Subject: [PATCH 1/2] Add NATS management to potctl: new potctl nats subcommand with accounts, users, account-rules, and user-rules (create, delete, describe, list, get-creds, ensure, operator). Remove the deprecated route resource and all route-related commands (delete, describe, rename, deploy, get). Update CLI docs for the new NATS commands and for user and account rules, and refresh go.mod/go.sum. --- docs/md/potctl.md | 1 + docs/md/potctl_delete.md | 6 +- docs/md/potctl_delete_nats-account-rule.md | 37 ++ docs/md/potctl_delete_nats-user-rule.md | 37 ++ docs/md/potctl_delete_role.md | 37 ++ docs/md/potctl_delete_rolebinding.md | 37 ++ docs/md/potctl_delete_serviceaccount.md | 37 ++ docs/md/potctl_deploy.md | 9 - docs/md/potctl_describe.md | 8 +- docs/md/potctl_describe_nats-account-rule.md | 32 ++ docs/md/potctl_describe_nats-account.md | 33 ++ docs/md/potctl_describe_nats-user-rule.md | 32 ++ docs/md/potctl_describe_nats-user.md | 33 ++ docs/md/potctl_describe_role.md | 38 ++ docs/md/potctl_describe_rolebinding.md | 38 ++ docs/md/potctl_describe_serviceaccount.md | 38 ++ docs/md/potctl_get.md | 8 +- docs/md/potctl_logs.md | 2 +- docs/md/potctl_nats.md | 39 ++ docs/md/potctl_nats_account-rules.md | 39 ++ .../potctl_nats_account-rules_create-yaml.md | 29 ++ docs/md/potctl_nats_account-rules_delete.md | 27 ++ docs/md/potctl_nats_account-rules_list.md | 28 ++ .../potctl_nats_account-rules_update-yaml.md | 29 ++ docs/md/potctl_nats_accounts.md | 34 ++ docs/md/potctl_nats_accounts_describe.md | 29 ++ docs/md/potctl_nats_accounts_ensure.md | 29 ++ docs/md/potctl_nats_accounts_list.md | 28 ++ docs/md/potctl_nats_operator.md | 28 ++ docs/md/potctl_nats_operator_describe.md | 29 ++ docs/md/potctl_nats_user-rules.md | 39 ++ docs/md/potctl_nats_user-rules_create-yaml.md | 29 ++ docs/md/potctl_nats_user-rules_delete.md | 27 ++ docs/md/potctl_nats_user-rules_list.md | 28 ++ docs/md/potctl_nats_user-rules_update-yaml.md | 29 ++ docs/md/potctl_nats_users.md | 40 ++ .../potctl_nats_users_create-mqtt-bearer.md | 30 ++ docs/md/potctl_nats_users_create.md | 30 ++ docs/md/potctl_nats_users_creds.md | 28 ++ .../potctl_nats_users_delete-mqtt-bearer.md | 27 ++ docs/md/potctl_nats_users_delete.md | 27 ++ docs/md/potctl_nats_users_describe.md | 29 ++ docs/md/potctl_nats_users_get-creds.md | 28 ++ docs/md/potctl_nats_users_list-account.md | 28 ++ docs/md/potctl_nats_users_list.md | 28 ++ docs/md/potctl_rename.md | 1 - go.mod | 34 +- go.sum | 68 ++-- internal/cmd/delete.go | 3 +- internal/cmd/delete_nats_account_rule.go | 31 ++ internal/cmd/delete_nats_user_rule.go | 31 ++ internal/cmd/delete_route.go | 47 --- internal/cmd/describe.go | 5 +- internal/cmd/describe_nats_account.go | 42 ++ internal/cmd/describe_nats_account_rule.go | 34 ++ internal/cmd/describe_nats_user.go | 44 +++ internal/cmd/describe_nats_user_rule.go | 34 ++ internal/cmd/describe_route.go | 52 --- internal/cmd/get.go | 12 +- internal/cmd/nats.go | 362 ++++++++++++++++++ internal/cmd/nats_rules_common.go | 41 ++ internal/cmd/rename.go | 1 - internal/cmd/rename_route.go | 45 --- internal/cmd/root.go | 1 + internal/config/types.go | 3 +- internal/delete/execute.go | 15 +- .../natsaccountrule/nats_account_rule.go | 32 ++ .../delete/natsuserrule/nats_user_rule.go | 32 ++ internal/delete/route/factory.go | 58 --- internal/deploy/agentconfig/utils.go | 20 + internal/deploy/edgeresource/factory.go | 2 +- internal/deploy/execute.go | 56 ++- internal/deploy/natsaccountrule/factory.go | 81 ++++ internal/deploy/natsuserrule/factory.go | 81 ++++ internal/deploy/route/factory.go | 98 ----- internal/describe/application.go | 35 +- internal/describe/factory.go | 2 - internal/describe/route.go | 99 ----- internal/describe/utils.go | 30 +- internal/exec/agent.go | 4 +- internal/execute/utils.go | 8 +- internal/get/all.go | 9 - internal/get/applications.go | 10 +- internal/get/factory.go | 10 +- internal/get/microservices.go | 7 +- internal/get/nats_account_rules.go | 41 ++ internal/get/nats_accounts.go | 50 +++ internal/get/nats_user_rules.go | 41 ++ internal/get/nats_users.go | 51 +++ internal/get/routes.go | 97 ----- internal/get/templates.go | 14 +- internal/rename/route/executor.go | 54 --- internal/resource/types.go | 1 - internal/util/client/api.go | 9 + pkg/iofog/constants.go | 1 + pkg/iofog/install/controller.go | 5 +- 96 files changed, 2518 insertions(+), 704 deletions(-) create mode 100644 docs/md/potctl_delete_nats-account-rule.md create mode 100644 docs/md/potctl_delete_nats-user-rule.md create mode 100644 docs/md/potctl_delete_role.md create mode 100644 docs/md/potctl_delete_rolebinding.md create mode 100644 docs/md/potctl_delete_serviceaccount.md create mode 100644 docs/md/potctl_describe_nats-account-rule.md create mode 100644 docs/md/potctl_describe_nats-account.md create mode 100644 docs/md/potctl_describe_nats-user-rule.md create mode 100644 docs/md/potctl_describe_nats-user.md create mode 100644 docs/md/potctl_describe_role.md create mode 100644 docs/md/potctl_describe_rolebinding.md create mode 100644 docs/md/potctl_describe_serviceaccount.md create mode 100644 docs/md/potctl_nats.md create mode 100644 docs/md/potctl_nats_account-rules.md create mode 100644 docs/md/potctl_nats_account-rules_create-yaml.md create mode 100644 docs/md/potctl_nats_account-rules_delete.md create mode 100644 docs/md/potctl_nats_account-rules_list.md create mode 100644 docs/md/potctl_nats_account-rules_update-yaml.md create mode 100644 docs/md/potctl_nats_accounts.md create mode 100644 docs/md/potctl_nats_accounts_describe.md create mode 100644 docs/md/potctl_nats_accounts_ensure.md create mode 100644 docs/md/potctl_nats_accounts_list.md create mode 100644 docs/md/potctl_nats_operator.md create mode 100644 docs/md/potctl_nats_operator_describe.md create mode 100644 docs/md/potctl_nats_user-rules.md create mode 100644 docs/md/potctl_nats_user-rules_create-yaml.md create mode 100644 docs/md/potctl_nats_user-rules_delete.md create mode 100644 docs/md/potctl_nats_user-rules_list.md create mode 100644 docs/md/potctl_nats_user-rules_update-yaml.md create mode 100644 docs/md/potctl_nats_users.md create mode 100644 docs/md/potctl_nats_users_create-mqtt-bearer.md create mode 100644 docs/md/potctl_nats_users_create.md create mode 100644 docs/md/potctl_nats_users_creds.md create mode 100644 docs/md/potctl_nats_users_delete-mqtt-bearer.md create mode 100644 docs/md/potctl_nats_users_delete.md create mode 100644 docs/md/potctl_nats_users_describe.md create mode 100644 docs/md/potctl_nats_users_get-creds.md create mode 100644 docs/md/potctl_nats_users_list-account.md create mode 100644 docs/md/potctl_nats_users_list.md create mode 100644 internal/cmd/delete_nats_account_rule.go create mode 100644 internal/cmd/delete_nats_user_rule.go delete mode 100644 internal/cmd/delete_route.go create mode 100644 internal/cmd/describe_nats_account.go create mode 100644 internal/cmd/describe_nats_account_rule.go create mode 100644 internal/cmd/describe_nats_user.go create mode 100644 internal/cmd/describe_nats_user_rule.go delete mode 100644 internal/cmd/describe_route.go create mode 100644 internal/cmd/nats.go create mode 100644 internal/cmd/nats_rules_common.go delete mode 100644 internal/cmd/rename_route.go create mode 100644 internal/delete/natsaccountrule/nats_account_rule.go create mode 100644 internal/delete/natsuserrule/nats_user_rule.go delete mode 100644 internal/delete/route/factory.go create mode 100644 internal/deploy/natsaccountrule/factory.go create mode 100644 internal/deploy/natsuserrule/factory.go delete mode 100644 internal/deploy/route/factory.go delete mode 100644 internal/describe/route.go create mode 100644 internal/get/nats_account_rules.go create mode 100644 internal/get/nats_accounts.go create mode 100644 internal/get/nats_user_rules.go create mode 100644 internal/get/nats_users.go delete mode 100644 internal/get/routes.go delete mode 100644 internal/rename/route/executor.go diff --git a/docs/md/potctl.md b/docs/md/potctl.md index 3cab28b..47e0f2b 100644 --- a/docs/md/potctl.md +++ b/docs/md/potctl.md @@ -32,6 +32,7 @@ potctl [flags] * [potctl legacy](potctl_legacy.md) - Execute commands using legacy CLI * [potctl logs](potctl_logs.md) - Get log contents of deployed resource * [potctl move](potctl_move.md) - Move an existing resources inside the current Namespace +* [potctl nats](potctl_nats.md) - Manage NATS resources * [potctl prune](potctl_prune.md) - prune ioFog resources * [potctl rebuild](potctl_rebuild.md) - Rebuilds a microservice or system-microservice * [potctl rename](potctl_rename.md) - Rename the iofog resources that are currently deployed diff --git a/docs/md/potctl_delete.md b/docs/md/potctl_delete.md index ce2c7ad..1df4bcf 100644 --- a/docs/md/potctl_delete.md +++ b/docs/md/potctl_delete.md @@ -39,10 +39,14 @@ potctl delete [flags] * [potctl delete edge-resource](potctl_delete_edge-resource.md) - Delete an Edge Resource * [potctl delete microservice](potctl_delete_microservice.md) - Delete a Microservice * [potctl delete namespace](potctl_delete_namespace.md) - Delete a Namespace +* [potctl delete nats-account-rule](potctl_delete_nats-account-rule.md) - Delete a NATS account rule +* [potctl delete nats-user-rule](potctl_delete_nats-user-rule.md) - Delete a NATS user rule * [potctl delete registry](potctl_delete_registry.md) - Delete a Registry -* [potctl delete route](potctl_delete_route.md) - Delete a Route +* [potctl delete role](potctl_delete_role.md) - Delete a Role +* [potctl delete rolebinding](potctl_delete_rolebinding.md) - Delete a RoleBinding * [potctl delete secret](potctl_delete_secret.md) - Delete a Secret * [potctl delete service](potctl_delete_service.md) - Delete a Service +* [potctl delete serviceaccount](potctl_delete_serviceaccount.md) - Delete a ServiceAccount * [potctl delete volume](potctl_delete_volume.md) - Delete an Volume * [potctl delete volume-mount](potctl_delete_volume-mount.md) - Delete a Volume Mount diff --git a/docs/md/potctl_delete_nats-account-rule.md b/docs/md/potctl_delete_nats-account-rule.md new file mode 100644 index 0000000..ad98f47 --- /dev/null +++ b/docs/md/potctl_delete_nats-account-rule.md @@ -0,0 +1,37 @@ +## potctl delete nats-account-rule + +Delete a NATS account rule + +### Synopsis + +Delete a NATS account rule from the Controller. + +``` +potctl delete nats-account-rule NAME [flags] +``` + +### Examples + +``` +potctl delete nats-account-rule NAME +``` + +### Options + +``` + -h, --help help for nats-account-rule +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl delete](potctl_delete.md) - Delete an existing ioFog resource + + diff --git a/docs/md/potctl_delete_nats-user-rule.md b/docs/md/potctl_delete_nats-user-rule.md new file mode 100644 index 0000000..272f288 --- /dev/null +++ b/docs/md/potctl_delete_nats-user-rule.md @@ -0,0 +1,37 @@ +## potctl delete nats-user-rule + +Delete a NATS user rule + +### Synopsis + +Delete a NATS user rule from the Controller. + +``` +potctl delete nats-user-rule NAME [flags] +``` + +### Examples + +``` +potctl delete nats-user-rule NAME +``` + +### Options + +``` + -h, --help help for nats-user-rule +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl delete](potctl_delete.md) - Delete an existing ioFog resource + + diff --git a/docs/md/potctl_delete_role.md b/docs/md/potctl_delete_role.md new file mode 100644 index 0000000..a288e7e --- /dev/null +++ b/docs/md/potctl_delete_role.md @@ -0,0 +1,37 @@ +## potctl delete role + +Delete a Role + +### Synopsis + +Delete a Role from the Controller. + +``` +potctl delete role NAME [flags] +``` + +### Examples + +``` +potctl delete role NAME +``` + +### Options + +``` + -h, --help help for role +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl delete](potctl_delete.md) - Delete an existing ioFog resource + + diff --git a/docs/md/potctl_delete_rolebinding.md b/docs/md/potctl_delete_rolebinding.md new file mode 100644 index 0000000..e21502c --- /dev/null +++ b/docs/md/potctl_delete_rolebinding.md @@ -0,0 +1,37 @@ +## potctl delete rolebinding + +Delete a RoleBinding + +### Synopsis + +Delete a RoleBinding from the Controller. + +``` +potctl delete rolebinding NAME [flags] +``` + +### Examples + +``` +potctl delete rolebinding NAME +``` + +### Options + +``` + -h, --help help for rolebinding +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl delete](potctl_delete.md) - Delete an existing ioFog resource + + diff --git a/docs/md/potctl_delete_serviceaccount.md b/docs/md/potctl_delete_serviceaccount.md new file mode 100644 index 0000000..3280e9d --- /dev/null +++ b/docs/md/potctl_delete_serviceaccount.md @@ -0,0 +1,37 @@ +## potctl delete serviceaccount + +Delete a ServiceAccount + +### Synopsis + +Delete a ServiceAccount from the Controller. + +``` +potctl delete serviceaccount NAME [flags] +``` + +### Examples + +``` +potctl delete serviceaccount NAME +``` + +### Options + +``` + -h, --help help for serviceaccount +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl delete](potctl_delete.md) - Delete an existing ioFog resource + + diff --git a/docs/md/potctl_deploy.md b/docs/md/potctl_deploy.md index 7595f1e..f670c54 100644 --- a/docs/md/potctl_deploy.md +++ b/docs/md/potctl_deploy.md @@ -7,15 +7,6 @@ Deploy Edge Compute Network components on existing infrastructure Deploy Edge Compute Network components on existing infrastructure. Visit iofog.org to view all YAML specifications usable with this command. -### Deployment requirements - -- **Container engine:** Deployments that run the agent or controller in a container require **Docker 25+** or **Podman 4+** on the target host. On Debian/Ubuntu/Raspbian and Fedora/CentOS/RHEL/OL/SLES/openSUSE, the deploy scripts can install a supported engine automatically. On other operating systems, you must install Docker 25+ or Podman 4+ yourself; the scripts will only verify presence and version, then configure and start the engine. -- **Native agent:** The **native** (package-managed) agent is supported only on **deb/rpm-based** distributions (**Debian, Ubuntu, Raspbian, Fedora, CentOS, RHEL, OL, SLES, openSUSE**) with **systemd**. On all other OSes or init systems, use the **container agent** on that host. -- **Container agent and controller:** The container-based agent and controller support multiple init systems. The install scripts detect the init system and install an appropriate service: - - **systemd:** systemd unit (Docker) or Quadlet unit (Podman) - - **sysvinit, openrc, s6, runit, upstart:** init-specific scripts that run the container with the same configuration -- **Airgap:** Airgap deployments do not install a container engine. The host must have Docker 25+ or Podman 4+ already installed; the script will detect which is available, verify the version, then configure and start it. - ``` potctl deploy [flags] ``` diff --git a/docs/md/potctl_describe.md b/docs/md/potctl_describe.md index 5b7fc00..906d24c 100644 --- a/docs/md/potctl_describe.md +++ b/docs/md/potctl_describe.md @@ -37,10 +37,16 @@ Most resources require a working Controller in the Namespace in order to be desc * [potctl describe edge-resource](potctl_describe_edge-resource.md) - Get detailed information about an Edge Resource * [potctl describe microservice](potctl_describe_microservice.md) - Get detailed information about a Microservice * [potctl describe namespace](potctl_describe_namespace.md) - Get detailed information about a Namespace +* [potctl describe nats-account](potctl_describe_nats-account.md) - Get detailed information about a NATS account +* [potctl describe nats-account-rule](potctl_describe_nats-account-rule.md) - Get detailed information about a NATS account rule +* [potctl describe nats-user](potctl_describe_nats-user.md) - Get detailed information about a NATS user +* [potctl describe nats-user-rule](potctl_describe_nats-user-rule.md) - Get detailed information about a NATS user rule * [potctl describe registry](potctl_describe_registry.md) - Get detailed information about a Microservice Registry -* [potctl describe route](potctl_describe_route.md) - Get detailed information about a Route +* [potctl describe role](potctl_describe_role.md) - Get detailed information about a Role +* [potctl describe rolebinding](potctl_describe_rolebinding.md) - Get detailed information about a RoleBinding * [potctl describe secret](potctl_describe_secret.md) - Get detailed information about a Secret * [potctl describe service](potctl_describe_service.md) - Get detailed information about a Service +* [potctl describe serviceaccount](potctl_describe_serviceaccount.md) - Get detailed information about a ServiceAccount * [potctl describe system-microservice](potctl_describe_system-microservice.md) - Get detailed information about a System Microservice * [potctl describe volume](potctl_describe_volume.md) - Get detailed information about a Volume * [potctl describe volume-mount](potctl_describe_volume-mount.md) - Get detailed information about a Volume Mount diff --git a/docs/md/potctl_describe_nats-account-rule.md b/docs/md/potctl_describe_nats-account-rule.md new file mode 100644 index 0000000..de72bf5 --- /dev/null +++ b/docs/md/potctl_describe_nats-account-rule.md @@ -0,0 +1,32 @@ +## potctl describe nats-account-rule + +Get detailed information about a NATS account rule + +### Synopsis + +Get detailed information about a NATS account rule. + +``` +potctl describe nats-account-rule NAME [flags] +``` + +### Options + +``` + -h, --help help for nats-account-rule + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_nats-account.md b/docs/md/potctl_describe_nats-account.md new file mode 100644 index 0000000..bc17d9f --- /dev/null +++ b/docs/md/potctl_describe_nats-account.md @@ -0,0 +1,33 @@ +## potctl describe nats-account + +Get detailed information about a NATS account + +### Synopsis + +Get detailed information about a NATS account. + +``` +potctl describe nats-account APP_NAME [flags] +``` + +### Options + +``` + -h, --help help for nats-account + --jwt Output decoded JWT payload only + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_nats-user-rule.md b/docs/md/potctl_describe_nats-user-rule.md new file mode 100644 index 0000000..c1c1000 --- /dev/null +++ b/docs/md/potctl_describe_nats-user-rule.md @@ -0,0 +1,32 @@ +## potctl describe nats-user-rule + +Get detailed information about a NATS user rule + +### Synopsis + +Get detailed information about a NATS user rule. + +``` +potctl describe nats-user-rule NAME [flags] +``` + +### Options + +``` + -h, --help help for nats-user-rule + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_nats-user.md b/docs/md/potctl_describe_nats-user.md new file mode 100644 index 0000000..9111c88 --- /dev/null +++ b/docs/md/potctl_describe_nats-user.md @@ -0,0 +1,33 @@ +## potctl describe nats-user + +Get detailed information about a NATS user + +### Synopsis + +Get detailed information about a NATS user. + +``` +potctl describe nats-user APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for nats-user + --jwt Output decoded JWT payload only + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_role.md b/docs/md/potctl_describe_role.md new file mode 100644 index 0000000..fdee502 --- /dev/null +++ b/docs/md/potctl_describe_role.md @@ -0,0 +1,38 @@ +## potctl describe role + +Get detailed information about a Role + +### Synopsis + +Get detailed information about a Role. + +``` +potctl describe role NAME [flags] +``` + +### Examples + +``` +potctl describe role NAME +``` + +### Options + +``` + -h, --help help for role + -o, --output-file string YAML output file +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_rolebinding.md b/docs/md/potctl_describe_rolebinding.md new file mode 100644 index 0000000..91acd8f --- /dev/null +++ b/docs/md/potctl_describe_rolebinding.md @@ -0,0 +1,38 @@ +## potctl describe rolebinding + +Get detailed information about a RoleBinding + +### Synopsis + +Get detailed information about a RoleBinding. + +``` +potctl describe rolebinding NAME [flags] +``` + +### Examples + +``` +potctl describe rolebinding NAME +``` + +### Options + +``` + -h, --help help for rolebinding + -o, --output-file string YAML output file +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_describe_serviceaccount.md b/docs/md/potctl_describe_serviceaccount.md new file mode 100644 index 0000000..c1f5b5d --- /dev/null +++ b/docs/md/potctl_describe_serviceaccount.md @@ -0,0 +1,38 @@ +## potctl describe serviceaccount + +Get detailed information about a ServiceAccount + +### Synopsis + +Get detailed information about a ServiceAccount. + +``` +potctl describe serviceaccount NAME [flags] +``` + +### Examples + +``` +potctl describe serviceaccount NAME +``` + +### Options + +``` + -h, --help help for serviceaccount + -o, --output-file string YAML output file +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl describe](potctl_describe.md) - Get detailed information of an existing resources + + diff --git a/docs/md/potctl_get.md b/docs/md/potctl_get.md index fab2987..3b24898 100644 --- a/docs/md/potctl_get.md +++ b/docs/md/potctl_get.md @@ -28,12 +28,18 @@ potctl get all catalog registries volumes - routes secrets configmaps services volume-mounts certificates + roles + rolebindings + serviceaccounts + nats-accounts + nats-users + nats-account-rules + nats-user-rules ``` ### Options diff --git a/docs/md/potctl_logs.md b/docs/md/potctl_logs.md index 4ba8be5..e132da1 100644 --- a/docs/md/potctl_logs.md +++ b/docs/md/potctl_logs.md @@ -15,7 +15,7 @@ potctl logs RESOURCE NAME [flags] ``` potctl logs controller NAME agent NAME - microservice NAME + microservice AppName/MsvcName ``` ### Options diff --git a/docs/md/potctl_nats.md b/docs/md/potctl_nats.md new file mode 100644 index 0000000..0e9bb48 --- /dev/null +++ b/docs/md/potctl_nats.md @@ -0,0 +1,39 @@ +## potctl nats + +Manage NATS resources + +### Synopsis + +Manage NATS-specific operations exposed by Controller APIs. Use get/describe/deploy/delete for CRUD-style NATS resources. + +### Examples + +``` +potctl nats operator describe +potctl nats accounts ensure my-app --nats-rule default-account-rule +potctl nats users create my-app service-user +potctl nats users creds my-app service-user +``` + +### Options + +``` + -h, --help help for nats +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl](potctl.md) - +* [potctl nats accounts](potctl_nats_accounts.md) - NATS account operations +* [potctl nats operator](potctl_nats_operator.md) - NATS operator operations +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_account-rules.md b/docs/md/potctl_nats_account-rules.md new file mode 100644 index 0000000..7d30d87 --- /dev/null +++ b/docs/md/potctl_nats_account-rules.md @@ -0,0 +1,39 @@ +## potctl nats account-rules + +NATS account rule operations + +### Synopsis + +List, create, update, and delete NATS account rules. + +### Examples + +``` +potctl nats account-rules list +potctl nats nats-account-rule create-yaml -f ./account-rule.yaml +potctl nats account-rule update-yaml default-account-rule -f ./account-rule.yaml +``` + +### Options + +``` + -h, --help help for account-rules +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats](potctl_nats.md) - Manage NATS resources +* [potctl nats account-rules create-yaml](potctl_nats_account-rules_create-yaml.md) - Create NATS account rule from YAML file +* [potctl nats account-rules delete](potctl_nats_account-rules_delete.md) - Delete NATS account rule +* [potctl nats account-rules list](potctl_nats_account-rules_list.md) - List NATS account rules +* [potctl nats account-rules update-yaml](potctl_nats_account-rules_update-yaml.md) - Update NATS account rule from YAML file + + diff --git a/docs/md/potctl_nats_account-rules_create-yaml.md b/docs/md/potctl_nats_account-rules_create-yaml.md new file mode 100644 index 0000000..7e3780d --- /dev/null +++ b/docs/md/potctl_nats_account-rules_create-yaml.md @@ -0,0 +1,29 @@ +## potctl nats account-rules create-yaml + +Create NATS account rule from YAML file + +``` +potctl nats account-rules create-yaml [flags] +``` + +### Options + +``` + -f, --file string NATS account rule YAML file path + -h, --help help for create-yaml + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats account-rules](potctl_nats_account-rules.md) - NATS account rule operations + + diff --git a/docs/md/potctl_nats_account-rules_delete.md b/docs/md/potctl_nats_account-rules_delete.md new file mode 100644 index 0000000..5108e4b --- /dev/null +++ b/docs/md/potctl_nats_account-rules_delete.md @@ -0,0 +1,27 @@ +## potctl nats account-rules delete + +Delete NATS account rule + +``` +potctl nats account-rules delete NAME [flags] +``` + +### Options + +``` + -h, --help help for delete +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats account-rules](potctl_nats_account-rules.md) - NATS account rule operations + + diff --git a/docs/md/potctl_nats_account-rules_list.md b/docs/md/potctl_nats_account-rules_list.md new file mode 100644 index 0000000..7f783c8 --- /dev/null +++ b/docs/md/potctl_nats_account-rules_list.md @@ -0,0 +1,28 @@ +## potctl nats account-rules list + +List NATS account rules + +``` +potctl nats account-rules list [flags] +``` + +### Options + +``` + -h, --help help for list + --output string Output format: yaml|json|wide (default "wide") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats account-rules](potctl_nats_account-rules.md) - NATS account rule operations + + diff --git a/docs/md/potctl_nats_account-rules_update-yaml.md b/docs/md/potctl_nats_account-rules_update-yaml.md new file mode 100644 index 0000000..67f3534 --- /dev/null +++ b/docs/md/potctl_nats_account-rules_update-yaml.md @@ -0,0 +1,29 @@ +## potctl nats account-rules update-yaml + +Update NATS account rule from YAML file + +``` +potctl nats account-rules update-yaml NAME [flags] +``` + +### Options + +``` + -f, --file string NATS account rule YAML file path + -h, --help help for update-yaml + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats account-rules](potctl_nats_account-rules.md) - NATS account rule operations + + diff --git a/docs/md/potctl_nats_accounts.md b/docs/md/potctl_nats_accounts.md new file mode 100644 index 0000000..222d2d9 --- /dev/null +++ b/docs/md/potctl_nats_accounts.md @@ -0,0 +1,34 @@ +## potctl nats accounts + +NATS account operations + +### Synopsis + +NATS-specific account actions for applications. + +### Examples + +``` +potctl nats accounts ensure my-application --nats-rule default-account-rule +``` + +### Options + +``` + -h, --help help for accounts +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats](potctl_nats.md) - Manage NATS resources +* [potctl nats accounts ensure](potctl_nats_accounts_ensure.md) - Ensure NATS account for application + + diff --git a/docs/md/potctl_nats_accounts_describe.md b/docs/md/potctl_nats_accounts_describe.md new file mode 100644 index 0000000..ff0e86d --- /dev/null +++ b/docs/md/potctl_nats_accounts_describe.md @@ -0,0 +1,29 @@ +## potctl nats accounts describe + +Describe NATS account for application + +``` +potctl nats accounts describe APP_NAME [flags] +``` + +### Options + +``` + -h, --help help for describe + --jwt Output decoded JWT payload only + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats accounts](potctl_nats_accounts.md) - NATS account operations + + diff --git a/docs/md/potctl_nats_accounts_ensure.md b/docs/md/potctl_nats_accounts_ensure.md new file mode 100644 index 0000000..ce29c7a --- /dev/null +++ b/docs/md/potctl_nats_accounts_ensure.md @@ -0,0 +1,29 @@ +## potctl nats accounts ensure + +Ensure NATS account for application + +``` +potctl nats accounts ensure APP_NAME [flags] +``` + +### Options + +``` + -h, --help help for ensure + --nats-rule string NATS account rule name + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats accounts](potctl_nats_accounts.md) - NATS account operations + + diff --git a/docs/md/potctl_nats_accounts_list.md b/docs/md/potctl_nats_accounts_list.md new file mode 100644 index 0000000..584207b --- /dev/null +++ b/docs/md/potctl_nats_accounts_list.md @@ -0,0 +1,28 @@ +## potctl nats accounts list + +List NATS accounts + +``` +potctl nats accounts list [flags] +``` + +### Options + +``` + -h, --help help for list + --output string Output format: yaml|json|wide (default "wide") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats accounts](potctl_nats_accounts.md) - NATS account operations + + diff --git a/docs/md/potctl_nats_operator.md b/docs/md/potctl_nats_operator.md new file mode 100644 index 0000000..b31cdf9 --- /dev/null +++ b/docs/md/potctl_nats_operator.md @@ -0,0 +1,28 @@ +## potctl nats operator + +NATS operator operations + +### Synopsis + +Inspect NATS operator metadata and JWT information. + +### Options + +``` + -h, --help help for operator +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats](potctl_nats.md) - Manage NATS resources +* [potctl nats operator describe](potctl_nats_operator_describe.md) - Describe NATS operator + + diff --git a/docs/md/potctl_nats_operator_describe.md b/docs/md/potctl_nats_operator_describe.md new file mode 100644 index 0000000..e01c0b3 --- /dev/null +++ b/docs/md/potctl_nats_operator_describe.md @@ -0,0 +1,29 @@ +## potctl nats operator describe + +Describe NATS operator + +``` +potctl nats operator describe [flags] +``` + +### Options + +``` + -h, --help help for describe + --jwt Output decoded JWT payload only + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats operator](potctl_nats_operator.md) - NATS operator operations + + diff --git a/docs/md/potctl_nats_user-rules.md b/docs/md/potctl_nats_user-rules.md new file mode 100644 index 0000000..ed73fb3 --- /dev/null +++ b/docs/md/potctl_nats_user-rules.md @@ -0,0 +1,39 @@ +## potctl nats user-rules + +NATS user rule operations + +### Synopsis + +List, create, update, and delete NATS user rules. + +### Examples + +``` +potctl nats user-rules list +potctl nats nats-user-rule create-yaml -f ./user-rule.yaml +potctl nats user-rule update-yaml default-user-rule -f ./user-rule.yaml +``` + +### Options + +``` + -h, --help help for user-rules +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats](potctl_nats.md) - Manage NATS resources +* [potctl nats user-rules create-yaml](potctl_nats_user-rules_create-yaml.md) - Create NATS user rule from YAML file +* [potctl nats user-rules delete](potctl_nats_user-rules_delete.md) - Delete NATS user rule +* [potctl nats user-rules list](potctl_nats_user-rules_list.md) - List NATS user rules +* [potctl nats user-rules update-yaml](potctl_nats_user-rules_update-yaml.md) - Update NATS user rule from YAML file + + diff --git a/docs/md/potctl_nats_user-rules_create-yaml.md b/docs/md/potctl_nats_user-rules_create-yaml.md new file mode 100644 index 0000000..74d6a29 --- /dev/null +++ b/docs/md/potctl_nats_user-rules_create-yaml.md @@ -0,0 +1,29 @@ +## potctl nats user-rules create-yaml + +Create NATS user rule from YAML file + +``` +potctl nats user-rules create-yaml [flags] +``` + +### Options + +``` + -f, --file string NATS user rule YAML file path + -h, --help help for create-yaml + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats user-rules](potctl_nats_user-rules.md) - NATS user rule operations + + diff --git a/docs/md/potctl_nats_user-rules_delete.md b/docs/md/potctl_nats_user-rules_delete.md new file mode 100644 index 0000000..309d73b --- /dev/null +++ b/docs/md/potctl_nats_user-rules_delete.md @@ -0,0 +1,27 @@ +## potctl nats user-rules delete + +Delete NATS user rule + +``` +potctl nats user-rules delete NAME [flags] +``` + +### Options + +``` + -h, --help help for delete +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats user-rules](potctl_nats_user-rules.md) - NATS user rule operations + + diff --git a/docs/md/potctl_nats_user-rules_list.md b/docs/md/potctl_nats_user-rules_list.md new file mode 100644 index 0000000..3cd035e --- /dev/null +++ b/docs/md/potctl_nats_user-rules_list.md @@ -0,0 +1,28 @@ +## potctl nats user-rules list + +List NATS user rules + +``` +potctl nats user-rules list [flags] +``` + +### Options + +``` + -h, --help help for list + --output string Output format: yaml|json|wide (default "wide") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats user-rules](potctl_nats_user-rules.md) - NATS user rule operations + + diff --git a/docs/md/potctl_nats_user-rules_update-yaml.md b/docs/md/potctl_nats_user-rules_update-yaml.md new file mode 100644 index 0000000..9a7e7a3 --- /dev/null +++ b/docs/md/potctl_nats_user-rules_update-yaml.md @@ -0,0 +1,29 @@ +## potctl nats user-rules update-yaml + +Update NATS user rule from YAML file + +``` +potctl nats user-rules update-yaml NAME [flags] +``` + +### Options + +``` + -f, --file string NATS user rule YAML file path + -h, --help help for update-yaml + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats user-rules](potctl_nats_user-rules.md) - NATS user rule operations + + diff --git a/docs/md/potctl_nats_users.md b/docs/md/potctl_nats_users.md new file mode 100644 index 0000000..b8a6fd1 --- /dev/null +++ b/docs/md/potctl_nats_users.md @@ -0,0 +1,40 @@ +## potctl nats users + +NATS user operations + +### Synopsis + +NATS-specific user actions such as create/delete and creds retrieval. + +### Examples + +``` +potctl nats users create my-application service-user +potctl nats users creds my-application service-user +potctl nats users creds my-application service-user -o ./service-user.creds +``` + +### Options + +``` + -h, --help help for users +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats](potctl_nats.md) - Manage NATS resources +* [potctl nats users create](potctl_nats_users_create.md) - Create NATS user under an application account +* [potctl nats users create-mqtt-bearer](potctl_nats_users_create-mqtt-bearer.md) - Create MQTT bearer NATS user +* [potctl nats users creds](potctl_nats_users_creds.md) - Fetch NATS creds +* [potctl nats users delete](potctl_nats_users_delete.md) - Delete NATS user from an application account +* [potctl nats users delete-mqtt-bearer](potctl_nats_users_delete-mqtt-bearer.md) - Delete MQTT bearer NATS user + + diff --git a/docs/md/potctl_nats_users_create-mqtt-bearer.md b/docs/md/potctl_nats_users_create-mqtt-bearer.md new file mode 100644 index 0000000..443c8f8 --- /dev/null +++ b/docs/md/potctl_nats_users_create-mqtt-bearer.md @@ -0,0 +1,30 @@ +## potctl nats users create-mqtt-bearer + +Create MQTT bearer NATS user + +``` +potctl nats users create-mqtt-bearer APP_NAME USER_NAME [flags] +``` + +### Options + +``` + --expires-in int Expiry in seconds + -h, --help help for create-mqtt-bearer + --nats-rule string NATS user rule name + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_create.md b/docs/md/potctl_nats_users_create.md new file mode 100644 index 0000000..89619e1 --- /dev/null +++ b/docs/md/potctl_nats_users_create.md @@ -0,0 +1,30 @@ +## potctl nats users create + +Create NATS user under an application account + +``` +potctl nats users create APP_NAME USER_NAME [flags] +``` + +### Options + +``` + --expires-in int Expiry in seconds + -h, --help help for create + --nats-rule string NATS user rule name + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_creds.md b/docs/md/potctl_nats_users_creds.md new file mode 100644 index 0000000..7415161 --- /dev/null +++ b/docs/md/potctl_nats_users_creds.md @@ -0,0 +1,28 @@ +## potctl nats users creds + +Fetch NATS creds + +``` +potctl nats users creds APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for creds + -o, --output-file string Destination creds file path (always overwritten) +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_delete-mqtt-bearer.md b/docs/md/potctl_nats_users_delete-mqtt-bearer.md new file mode 100644 index 0000000..b73a0f7 --- /dev/null +++ b/docs/md/potctl_nats_users_delete-mqtt-bearer.md @@ -0,0 +1,27 @@ +## potctl nats users delete-mqtt-bearer + +Delete MQTT bearer NATS user + +``` +potctl nats users delete-mqtt-bearer APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for delete-mqtt-bearer +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_delete.md b/docs/md/potctl_nats_users_delete.md new file mode 100644 index 0000000..ba4a237 --- /dev/null +++ b/docs/md/potctl_nats_users_delete.md @@ -0,0 +1,27 @@ +## potctl nats users delete + +Delete NATS user from an application account + +``` +potctl nats users delete APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for delete +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_describe.md b/docs/md/potctl_nats_users_describe.md new file mode 100644 index 0000000..6abeadb --- /dev/null +++ b/docs/md/potctl_nats_users_describe.md @@ -0,0 +1,29 @@ +## potctl nats users describe + +Describe NATS user in application account + +``` +potctl nats users describe APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for describe + --jwt Output decoded JWT payload only + --output string Output format: yaml|json|wide (default "yaml") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_get-creds.md b/docs/md/potctl_nats_users_get-creds.md new file mode 100644 index 0000000..dd22ade --- /dev/null +++ b/docs/md/potctl_nats_users_get-creds.md @@ -0,0 +1,28 @@ +## potctl nats users get-creds + +Fetch NATS creds and save to file + +``` +potctl nats users get-creds APP_NAME USER_NAME [flags] +``` + +### Options + +``` + -h, --help help for get-creds + -o, --output-file string Destination creds file path (always overwritten) +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_list-account.md b/docs/md/potctl_nats_users_list-account.md new file mode 100644 index 0000000..a80e55d --- /dev/null +++ b/docs/md/potctl_nats_users_list-account.md @@ -0,0 +1,28 @@ +## potctl nats users list-account + +List NATS users for an application account + +``` +potctl nats users list-account APP_NAME [flags] +``` + +### Options + +``` + -h, --help help for list-account + --output string Output format: yaml|json|wide (default "wide") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_nats_users_list.md b/docs/md/potctl_nats_users_list.md new file mode 100644 index 0000000..423b270 --- /dev/null +++ b/docs/md/potctl_nats_users_list.md @@ -0,0 +1,28 @@ +## potctl nats users list + +List all NATS users + +``` +potctl nats users list [flags] +``` + +### Options + +``` + -h, --help help for list + --output string Output format: yaml|json|wide (default "wide") +``` + +### Options inherited from parent commands + +``` + --debug Toggle for displaying verbose output of API clients (HTTP and SSH) + -n, --namespace string Namespace to execute respective command within (default "default") + -v, --verbose Toggle for displaying verbose output of potctl +``` + +### SEE ALSO + +* [potctl nats users](potctl_nats_users.md) - NATS user operations + + diff --git a/docs/md/potctl_rename.md b/docs/md/potctl_rename.md index 36a7ad8..22195a9 100644 --- a/docs/md/potctl_rename.md +++ b/docs/md/potctl_rename.md @@ -29,6 +29,5 @@ Rename the iofog resources that are currently deployed * [potctl rename edge-resource](potctl_rename_edge-resource.md) - Rename an Edge Resource * [potctl rename microservice](potctl_rename_microservice.md) - Rename a Microservice * [potctl rename namespace](potctl_rename_namespace.md) - Rename a Namespace -* [potctl rename route](potctl_rename_route.md) - Rename a Route diff --git a/go.mod b/go.mod index 3d05f94..a237bc5 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,18 @@ module github.com/datasance/potctl -go 1.23.0 +go 1.24.0 -toolchain go1.23.2 +toolchain go1.24.3 require ( github.com/GeertJohan/go.rice v1.0.2 github.com/briandowns/spinner v1.23.1 github.com/containers/image/v5 v5.32.1 - github.com/datasance/iofog-go-sdk/v3 v3.6.0 - github.com/datasance/iofog-operator/v3 v3.6.0 + github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0 + github.com/datasance/iofog-operator/v3 v3.7.0-beta.0 github.com/docker/docker v27.4.1+incompatible github.com/docker/go-connections v0.5.0 github.com/gorilla/websocket v1.5.3 - github.com/json-iterator/go v1.1.12 github.com/mitchellh/go-homedir v1.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -21,16 +20,16 @@ require ( github.com/spf13/cobra v1.8.1 github.com/twmb/algoimpl v0.0.0-20170717182524-076353e90b94 github.com/vmihailenco/msgpack/v5 v5.4.1 - golang.org/x/crypto v0.41.0 + golang.org/x/crypto v0.46.0 golang.org/x/oauth2 v0.23.0 - golang.org/x/sys v0.35.0 - golang.org/x/term v0.34.0 + golang.org/x/sys v0.40.0 + golang.org/x/term v0.39.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.32.0 - k8s.io/apiextensions-apiserver v0.32.0 - k8s.io/apimachinery v0.32.0 - k8s.io/client-go v0.32.0 - sigs.k8s.io/controller-runtime v0.19.3 + k8s.io/api v0.32.1 + k8s.io/apiextensions-apiserver v0.32.1 + k8s.io/apimachinery v0.32.1 + k8s.io/client-go v0.32.1 + sigs.k8s.io/controller-runtime v0.20.4 ) require ( @@ -58,7 +57,7 @@ require ( github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -89,6 +88,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/kr/fs v0.1.0 // indirect @@ -143,9 +143,9 @@ require ( go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.7.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/grpc v1.68.1 // indirect diff --git a/go.sum b/go.sum index d2955ff..e53f6a1 100644 --- a/go.sum +++ b/go.sum @@ -58,10 +58,10 @@ github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzw github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M= github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= -github.com/datasance/iofog-go-sdk/v3 v3.6.0 h1:HQ7AK3FrNDirgL8Kp5FPsfmRtdTImu+BXV36bZPGFqs= -github.com/datasance/iofog-go-sdk/v3 v3.6.0/go.mod h1:Gx/T77nGu3QvC93c96IDMEHJ2cdqZA84icl7R87ds84= -github.com/datasance/iofog-operator/v3 v3.6.0 h1:x6yTqcc5yU+V7y2t+cedAEKXlf/bX8pCyXIp8WJKd30= -github.com/datasance/iofog-operator/v3 v3.6.0/go.mod h1:AsuO2MiVpwnn74xxqalYlRiqHHluVUykN6zKIHQF8hg= +github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0 h1:rRbLMsvVoZvuzthV0c4Rt+9Xu/whYqGWFETQSZeztss= +github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0/go.mod h1:mLHD3oHazNzKsV8HoWDsI4g613fHs+rKPUFtYf0tB/U= +github.com/datasance/iofog-operator/v3 v3.7.0-beta.0 h1:Hj5q7F4ysCY75n5GGLuye0fOmc/rEFVXeHkx//8ZQz8= +github.com/datasance/iofog-operator/v3 v3.7.0-beta.0/go.mod h1:FvptSLzx4itiRYmGecx8zA+LpEnqRWuz1a1GzB7Rypc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -88,8 +88,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -245,10 +245,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -379,8 +379,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -398,8 +398,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -408,8 +408,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -418,14 +418,14 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -436,8 +436,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -488,22 +488,22 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE= -k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0= -k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0= -k8s.io/apiextensions-apiserver v0.32.0/go.mod h1:86hblMvN5yxMvZrZFX2OhIHAuFIMJIZ19bTvzkP+Fmw= -k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg= -k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8= -k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8= +k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= +k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= +k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+6UXZw= +k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto= +k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= +k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= +k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= -sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= diff --git a/internal/cmd/delete.go b/internal/cmd/delete.go index 476fadb..5f74e0c 100644 --- a/internal/cmd/delete.go +++ b/internal/cmd/delete.go @@ -60,13 +60,14 @@ func newDeleteCommand() *cobra.Command { newDeleteRegistryCommand(), newDeleteMicroserviceCommand(), newDeleteVolumeCommand(), - newDeleteRouteCommand(), newDeleteEdgeResourceCommand(), newDeleteSecretCommand(), newDeleteConfigMapCommand(), newDeleteRoleCommand(), newDeleteRoleBindingCommand(), newDeleteServiceAccountCommand(), + newDeleteNatsAccountRuleCommand(), + newDeleteNatsUserRuleCommand(), newDeleteServiceCommand(), newDeleteVolumeMountCommand(), newDeleteCertificateCommand(), diff --git a/internal/cmd/delete_nats_account_rule.go b/internal/cmd/delete_nats_account_rule.go new file mode 100644 index 0000000..696ccdb --- /dev/null +++ b/internal/cmd/delete_nats_account_rule.go @@ -0,0 +1,31 @@ +package cmd + +import ( + deletenatsaccountrule "github.com/datasance/potctl/internal/delete/natsaccountrule" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDeleteNatsAccountRuleCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "nats-account-rule NAME", + Short: "Delete a NATS account rule", + Long: `Delete a NATS account rule from the Controller.`, + Example: `potctl delete nats-account-rule NAME`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + exe, err := deletenatsaccountrule.NewExecutor(namespace, name) + util.Check(err) + err = exe.Execute() + util.Check(err) + + util.PrintSuccess("Successfully deleted NATS account rule " + name) + }, + } + + return cmd +} diff --git a/internal/cmd/delete_nats_user_rule.go b/internal/cmd/delete_nats_user_rule.go new file mode 100644 index 0000000..47b4a7b --- /dev/null +++ b/internal/cmd/delete_nats_user_rule.go @@ -0,0 +1,31 @@ +package cmd + +import ( + deletenatsuserrule "github.com/datasance/potctl/internal/delete/natsuserrule" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDeleteNatsUserRuleCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "nats-user-rule NAME", + Short: "Delete a NATS user rule", + Long: `Delete a NATS user rule from the Controller.`, + Example: `potctl delete nats-user-rule NAME`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + exe, err := deletenatsuserrule.NewExecutor(namespace, name) + util.Check(err) + err = exe.Execute() + util.Check(err) + + util.PrintSuccess("Successfully deleted NATS user rule " + name) + }, + } + + return cmd +} diff --git a/internal/cmd/delete_route.go b/internal/cmd/delete_route.go deleted file mode 100644 index 35e1135..0000000 --- a/internal/cmd/delete_route.go +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package cmd - -import ( - delete "github.com/datasance/potctl/internal/delete/route" - "github.com/datasance/potctl/pkg/util" - "github.com/spf13/cobra" -) - -func newDeleteRouteCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "route NAME", - Short: "Delete a Route", - Long: `Delete a Route. - -The corresponding Microservices will no longer be able to reach each other using ioMessages.`, - Example: `potctl delete route NAME`, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - // Get name and namespace of route - name := args[0] - namespace, err := cmd.Flags().GetString("namespace") - util.Check(err) - - // Run the command - exe := delete.NewExecutor(namespace, name) - err = exe.Execute() - util.Check(err) - - util.PrintSuccess("Successfully deleted " + namespace + "/" + name) - }, - } - - return cmd -} diff --git a/internal/cmd/describe.go b/internal/cmd/describe.go index 844f69d..9a96623 100644 --- a/internal/cmd/describe.go +++ b/internal/cmd/describe.go @@ -41,7 +41,6 @@ Most resources require a working Controller in the Namespace in order to be desc newDescribeApplicationCommand(), newDescribeApplicationTemplateCommand(), newDescribeVolumeCommand(), - newDescribeRouteCommand(), newDescribeEdgeResourceCommand(), newDescribeSecretCommand(), newDescribeConfigMapCommand(), @@ -51,6 +50,10 @@ Most resources require a working Controller in the Namespace in order to be desc newDescribeRoleCommand(), newDescribeRoleBindingCommand(), newDescribeServiceAccountCommand(), + newDescribeNatsAccountCommand(), + newDescribeNatsUserCommand(), + newDescribeNatsAccountRuleCommand(), + newDescribeNatsUserRuleCommand(), ) // Register Flags diff --git a/internal/cmd/describe_nats_account.go b/internal/cmd/describe_nats_account.go new file mode 100644 index 0000000..46b6f6d --- /dev/null +++ b/internal/cmd/describe_nats_account.go @@ -0,0 +1,42 @@ +package cmd + +import ( + "fmt" + + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDescribeNatsAccountCommand() *cobra.Command { + output := natsOutputYAML + jwtOnly := false + cmd := &cobra.Command{ + Use: "nats-account APP_NAME", + Short: "Get detailed information about a NATS account", + Long: "Get detailed information about a NATS account.", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + account, err := clt.GetNatsAccount(args[0]) + util.Check(err) + + if jwtOnly { + printDecodedJWT(account.JWT, output) + return + } + table := [][]string{ + {"NAME", "APP ID", "SYSTEM", "PUBLIC KEY", "JWT"}, + {account.Name, fmt.Sprintf("%d", account.ApplicationID), fmt.Sprintf("%t", account.IsSystem), account.PublicKey, account.JWT}, + } + util.Check(printNatsOutput(account, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().BoolVar(&jwtOnly, "jwt", false, "Output decoded JWT payload only") + return cmd +} diff --git a/internal/cmd/describe_nats_account_rule.go b/internal/cmd/describe_nats_account_rule.go new file mode 100644 index 0000000..f254e32 --- /dev/null +++ b/internal/cmd/describe_nats_account_rule.go @@ -0,0 +1,34 @@ +package cmd + +import ( + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDescribeNatsAccountRuleCommand() *cobra.Command { + output := natsOutputYAML + cmd := &cobra.Command{ + Use: "nats-account-rule NAME", + Short: "Get detailed information about a NATS account rule", + Long: "Get detailed information about a NATS account rule.", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + response, err := clt.ListNatsAccountRules() + util.Check(err) + + rule, err := findNatsRuleByName(response.Rules, args[0]) + util.Check(err) + manifest := buildNatsRuleManifest("NatsAccountRule", rule) + table := [][]string{{"NAME"}, {rule.Name}} + util.Check(printNatsOutput(manifest, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + return cmd +} diff --git a/internal/cmd/describe_nats_user.go b/internal/cmd/describe_nats_user.go new file mode 100644 index 0000000..7301805 --- /dev/null +++ b/internal/cmd/describe_nats_user.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "fmt" + + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDescribeNatsUserCommand() *cobra.Command { + output := natsOutputYAML + jwtOnly := false + cmd := &cobra.Command{ + Use: "nats-user APP_NAME USER_NAME", + Short: "Get detailed information about a NATS user", + Long: "Get detailed information about a NATS user.", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + users, err := clt.ListNatsAccountUsers(args[0]) + util.Check(err) + user, err := findNatsUserByName(users.Users, args[1]) + util.Check(err) + + if jwtOnly { + printDecodedJWT(user.JWT, output) + return + } + table := [][]string{ + {"NAME", "BEARER", "PUBLIC KEY", "JWT"}, + {user.Name, fmt.Sprintf("%t", user.IsBearer), user.PublicKey, user.JWT}, + } + util.Check(printNatsOutput(user, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().BoolVar(&jwtOnly, "jwt", false, "Output decoded JWT payload only") + return cmd +} diff --git a/internal/cmd/describe_nats_user_rule.go b/internal/cmd/describe_nats_user_rule.go new file mode 100644 index 0000000..a0a642f --- /dev/null +++ b/internal/cmd/describe_nats_user_rule.go @@ -0,0 +1,34 @@ +package cmd + +import ( + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +func newDescribeNatsUserRuleCommand() *cobra.Command { + output := natsOutputYAML + cmd := &cobra.Command{ + Use: "nats-user-rule NAME", + Short: "Get detailed information about a NATS user rule", + Long: "Get detailed information about a NATS user rule.", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + response, err := clt.ListNatsUserRules() + util.Check(err) + + rule, err := findNatsRuleByName(response.Rules, args[0]) + util.Check(err) + manifest := buildNatsRuleManifest("NatsUserRule", rule) + table := [][]string{{"NAME"}, {rule.Name}} + util.Check(printNatsOutput(manifest, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + return cmd +} diff --git a/internal/cmd/describe_route.go b/internal/cmd/describe_route.go deleted file mode 100644 index 3a2dabb..0000000 --- a/internal/cmd/describe_route.go +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package cmd - -import ( - "github.com/datasance/potctl/internal/describe" - "github.com/datasance/potctl/pkg/util" - "github.com/spf13/cobra" -) - -func newDescribeRouteCommand() *cobra.Command { - opt := describe.Options{ - Resource: "route", - } - - cmd := &cobra.Command{ - Use: "route NAME", - Short: "Get detailed information about a Route", - Long: `Get detailed information about a Route.`, - Example: `potctl describe route NAME`, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - // Get resource type and name - var err error - opt.Name = args[0] - opt.Namespace, err = cmd.Flags().GetString("namespace") - util.Check(err) - - // Get executor for describe command - exe, err := describe.NewExecutor(&opt) - util.Check(err) - - // Execute the command - err = exe.Execute() - util.Check(err) - }, - } - cmd.Flags().StringVarP(&opt.Filename, "output-file", "o", "", "YAML output file") - - return cmd -} diff --git a/internal/cmd/get.go b/internal/cmd/get.go index 760d5d4..5f2e31d 100644 --- a/internal/cmd/get.go +++ b/internal/cmd/get.go @@ -37,7 +37,6 @@ func newGetCommand() *cobra.Command { "catalog", "registries", "volumes", - "routes", "secrets", "configmaps", "services", @@ -46,6 +45,10 @@ func newGetCommand() *cobra.Command { "roles", "rolebindings", "serviceaccounts", + "nats-accounts", + "nats-users", + "nats-account-rules", + "nats-user-rules", } cmd := &cobra.Command{ Use: "get RESOURCE", @@ -66,7 +69,6 @@ Resources like Agents will require a working Controller in the namespace to disp catalog registries volumes - routes secrets configmaps services @@ -74,7 +76,11 @@ Resources like Agents will require a working Controller in the namespace to disp certificates roles rolebindings - serviceaccounts`, + serviceaccounts + nats-accounts + nats-users + nats-account-rules + nats-user-rules`, ValidArgs: validResources, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { diff --git a/internal/cmd/nats.go b/internal/cmd/nats.go new file mode 100644 index 0000000..54912e0 --- /dev/null +++ b/internal/cmd/nats.go @@ -0,0 +1,362 @@ +package cmd + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "os" + "strings" + "text/tabwriter" + + "github.com/datasance/iofog-go-sdk/v3/pkg/client" + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "github.com/spf13/cobra" +) + +const ( + natsOutputYAML = "yaml" + natsOutputJSON = "json" + natsOutputWide = "wide" +) + +func newNatsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "nats", + Short: "Manage NATS resources", + Long: "Manage NATS-specific operations exposed by Controller APIs. Use get/describe/deploy/delete for CRUD-style NATS resources.", + Example: `potctl nats operator describe +potctl nats accounts ensure my-app --nats-rule default-account-rule +potctl nats users create my-app service-user +potctl nats users creds my-app service-user`, + } + + cmd.AddCommand( + newNatsOperatorCommand(), + newNatsAccountsCommand(), + newNatsUsersCommand(), + ) + + return cmd +} + +func newNatsOperatorCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "operator", + Short: "NATS operator operations", + Long: "Inspect NATS operator metadata and JWT information.", + } + cmd.AddCommand(newNatsOperatorDescribeCommand()) + return cmd +} + +func newNatsOperatorDescribeCommand() *cobra.Command { + output := natsOutputYAML + jwtOnly := false + cmd := &cobra.Command{ + Use: "describe", + Short: "Describe NATS operator", + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + operator, err := clt.GetNatsOperator() + util.Check(err) + + if jwtOnly { + printDecodedJWT(operator.JWT, output) + return + } + + wide := [][]string{ + {"NAME", "PUBLIC KEY", "JWT"}, + {operator.Name, operator.PublicKey, operator.JWT}, + } + util.Check(printNatsOutput(operator, output, wide)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().BoolVar(&jwtOnly, "jwt", false, "Output decoded JWT payload only") + return cmd +} + +func newNatsAccountsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "accounts", + Aliases: []string{"account"}, + Short: "NATS account operations", + Long: "NATS-specific account actions for applications.", + Example: `potctl nats accounts ensure my-application --nats-rule default-account-rule`, + } + cmd.AddCommand( + newNatsAccountsEnsureCommand(), + ) + return cmd +} + +func newNatsAccountsEnsureCommand() *cobra.Command { + output := natsOutputYAML + natsRule := "" + cmd := &cobra.Command{ + Use: "ensure APP_NAME", + Short: "Ensure NATS account for application", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + req := &client.NatsEnsureAccountRequest{} + if natsRule != "" { + req.NatsRule = natsRule + } + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + account, err := clt.EnsureNatsAccount(args[0], req) + util.Check(err) + + table := [][]string{ + {"NAME", "APP ID", "SYSTEM", "PUBLIC KEY"}, + {account.Name, fmt.Sprintf("%d", account.ApplicationID), fmt.Sprintf("%t", account.IsSystem), account.PublicKey}, + } + util.Check(printNatsOutput(account, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().StringVar(&natsRule, "nats-rule", "", "NATS account rule name") + return cmd +} + +func newNatsUsersCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "users", + Aliases: []string{"user"}, + Short: "NATS user operations", + Long: "NATS-specific user actions such as create/delete and creds retrieval.", + Example: `potctl nats users create my-application service-user +potctl nats users creds my-application service-user +potctl nats users creds my-application service-user -o ./service-user.creds`, + } + cmd.AddCommand( + newNatsUsersCreateCommand(), + newNatsUsersDeleteCommand(), + newNatsUsersCreateMqttBearerCommand(), + newNatsUsersDeleteMqttBearerCommand(), + newNatsUsersCredsCommand(), + ) + return cmd +} + +func newNatsUsersCreateCommand() *cobra.Command { + output := natsOutputYAML + var expiresIn int64 + natsRule := "" + cmd := &cobra.Command{ + Use: "create APP_NAME USER_NAME", + Short: "Create NATS user under an application account", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + req := &client.NatsCreateUserRequest{ + Name: args[1], + } + if expiresIn > 0 { + req.ExpiresIn = &expiresIn + } + if natsRule != "" { + req.NatsRule = natsRule + } + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + user, err := clt.CreateNatsUser(args[0], req) + util.Check(err) + + table := [][]string{ + {"NAME", "BEARER", "PUBLIC KEY"}, + {user.Name, fmt.Sprintf("%t", user.IsBearer), user.PublicKey}, + } + util.Check(printNatsOutput(user, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().Int64Var(&expiresIn, "expires-in", 0, "Expiry in seconds") + cmd.Flags().StringVar(&natsRule, "nats-rule", "", "NATS user rule name") + return cmd +} + +func newNatsUsersDeleteCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete APP_NAME USER_NAME", + Short: "Delete NATS user from an application account", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + err = clt.DeleteNatsUser(args[0], args[1]) + util.Check(err) + util.PrintSuccess(fmt.Sprintf("Deleted NATS user %s/%s", args[0], args[1])) + }, + } + return cmd +} + +func newNatsUsersCreateMqttBearerCommand() *cobra.Command { + output := natsOutputYAML + var expiresIn int64 + natsRule := "" + cmd := &cobra.Command{ + Use: "create-mqtt-bearer APP_NAME USER_NAME", + Short: "Create MQTT bearer NATS user", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + req := &client.NatsCreateMqttBearerRequest{ + Name: args[1], + } + if expiresIn > 0 { + req.ExpiresIn = &expiresIn + } + if natsRule != "" { + req.NatsRule = natsRule + } + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + user, err := clt.CreateNatsMqttBearer(args[0], req) + util.Check(err) + + table := [][]string{ + {"NAME", "PUBLIC KEY", "JWT"}, + {user.Name, user.PublicKey, user.JWT}, + } + util.Check(printNatsOutput(user, output, table)) + }, + } + cmd.Flags().StringVarP(&output, "output", "", natsOutputYAML, "Output format: yaml|json|wide") + cmd.Flags().Int64Var(&expiresIn, "expires-in", 0, "Expiry in seconds") + cmd.Flags().StringVar(&natsRule, "nats-rule", "", "NATS user rule name") + return cmd +} + +func newNatsUsersDeleteMqttBearerCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete-mqtt-bearer APP_NAME USER_NAME", + Short: "Delete MQTT bearer NATS user", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + err = clt.DeleteNatsMqttBearer(args[0], args[1]) + util.Check(err) + util.PrintSuccess(fmt.Sprintf("Deleted MQTT bearer user %s/%s", args[0], args[1])) + }, + } + return cmd +} + +func newNatsUsersCredsCommand() *cobra.Command { + outputFile := "" + cmd := &cobra.Command{ + Use: "creds APP_NAME USER_NAME", + Aliases: []string{"get-creds"}, + Short: "Fetch NATS creds", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + namespace, err := cmd.Flags().GetString("namespace") + util.Check(err) + + clt, err := clientutil.NewControllerClient(namespace) + util.Check(err) + credsResponse, err := clt.GetNatsUserCreds(args[0], args[1]) + util.Check(err) + + decoded, err := base64.StdEncoding.DecodeString(credsResponse.CredsBase64) + util.Check(err) + if strings.TrimSpace(outputFile) == "" { + _, err = os.Stdout.Write(decoded) + util.Check(err) + return + } + err = os.WriteFile(outputFile, decoded, 0600) + util.Check(err) + util.PrintSuccess(fmt.Sprintf("Saved NATS creds to %s", outputFile)) + }, + } + cmd.Flags().StringVarP(&outputFile, "output-file", "o", "", "Destination creds file path (always overwritten)") + return cmd +} + +func printNatsOutput(obj interface{}, output string, wide [][]string) error { + switch strings.ToLower(output) { + case natsOutputYAML: + return util.Print(obj) + case natsOutputJSON: + j, err := json.MarshalIndent(obj, "", " ") + if err != nil { + return err + } + _, err = fmt.Fprintln(os.Stdout, string(j)) + return err + case natsOutputWide: + if len(wide) == 0 { + return nil + } + return printWideTable(wide) + default: + return util.NewInputError("invalid --output, use yaml|json|wide") + } +} + +func printWideTable(table [][]string) error { + writer := tabwriter.NewWriter(os.Stdout, 16, 8, 1, '\t', 0) + defer writer.Flush() + for _, row := range table { + for _, col := range row { + if _, err := fmt.Fprintf(writer, "%s\t", col); err != nil { + return err + } + } + if _, err := fmt.Fprintln(writer); err != nil { + return err + } + } + _, err := fmt.Fprintln(writer) + return err +} + +func findNatsUserByName(users []client.NatsUserInfo, name string) (client.NatsUserInfo, error) { + for _, user := range users { + if user.Name == name { + return user, nil + } + } + return client.NatsUserInfo{}, util.NewNotFoundError(fmt.Sprintf("NATS user not found: %s", name)) +} + +func printDecodedJWT(token, output string) { + parts := strings.Split(token, ".") + if len(parts) < 2 { + util.Check(util.NewInputError("invalid JWT token")) + return + } + + payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1]) + util.Check(err) + + var payload interface{} + err = json.Unmarshal(payloadBytes, &payload) + util.Check(err) + + util.Check(printNatsOutput(payload, output, nil)) +} diff --git a/internal/cmd/nats_rules_common.go b/internal/cmd/nats_rules_common.go new file mode 100644 index 0000000..17db8cc --- /dev/null +++ b/internal/cmd/nats_rules_common.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "encoding/json" + "fmt" + + "github.com/datasance/iofog-go-sdk/v3/pkg/client" + "github.com/datasance/potctl/pkg/util" +) + +func findNatsRuleByName(rules []client.NatsRuleInfo, name string) (client.NatsRuleInfo, error) { + for _, rule := range rules { + if rule.Name == name { + return rule, nil + } + } + return client.NatsRuleInfo{}, util.NewNotFoundError(fmt.Sprintf("NATS rule not found: %s", name)) +} + +func buildNatsRuleManifest(kind string, rule client.NatsRuleInfo) map[string]interface{} { + b, err := json.Marshal(rule) + util.Check(err) + + spec := map[string]interface{}{} + err = json.Unmarshal(b, &spec) + util.Check(err) + + // Keep rule manifests Controller-compatible: identity belongs in metadata. + delete(spec, "id") + delete(spec, "name") + delete(spec, "isSystem") + + return map[string]interface{}{ + "apiVersion": "datasance.com/v3", + "kind": kind, + "metadata": map[string]interface{}{ + "name": rule.Name, + }, + "spec": spec, + } +} diff --git a/internal/cmd/rename.go b/internal/cmd/rename.go index 657e615..e22c6c0 100644 --- a/internal/cmd/rename.go +++ b/internal/cmd/rename.go @@ -32,7 +32,6 @@ func newRenameCommand() *cobra.Command { newRenameAgentCommand(), newRenameApplicationCommand(), newRenameMicroserviceCommand(), - newRenameRouteCommand(), newRenameEdgeResourceCommand(), ) diff --git a/internal/cmd/rename_route.go b/internal/cmd/rename_route.go deleted file mode 100644 index 76b1521..0000000 --- a/internal/cmd/rename_route.go +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package cmd - -import ( - rename "github.com/datasance/potctl/internal/rename/route" - "github.com/datasance/potctl/pkg/util" - "github.com/spf13/cobra" -) - -func newRenameRouteCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "route NAME NEW_NAME", - Short: "Rename a Route", - Long: `Rename a Route`, - Example: `potctl rename route NAME NEW_NAME`, - Args: cobra.ExactArgs(2), - Run: func(cmd *cobra.Command, args []string) { - // Get name and new name of the route - name := args[0] - newName := args[1] - namespace, err := cmd.Flags().GetString("namespace") - util.Check(err) - - // Get an executor for the command - err = rename.Execute(namespace, name, newName) - util.Check(err) - - util.PrintSuccess(getRenameSuccessMessage("Route", name, newName)) - }, - } - - return cmd -} diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 9697ed9..3208119 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -91,6 +91,7 @@ func NewRootCommand() *cobra.Command { newUpgradeCommand(), newRollbackCommand(), newExecCommand(), + newNatsCommand(), ) return cmd diff --git a/internal/config/types.go b/internal/config/types.go index 2e3fcbf..a9bfffd 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -25,7 +25,8 @@ const ( MicroserviceKind Kind = Kind(apps.MicroserviceKind) ApplicationKind Kind = Kind(apps.ApplicationKind) ApplicationTemplateKind Kind = Kind(apps.ApplicationTemplateKind) - RouteKind Kind = Kind(apps.RouteKind) + NatsAccountRuleKind Kind = "NatsAccountRule" + NatsUserRuleKind Kind = "NatsUserRule" SecretKind Kind = "Secret" ConfigMapKind Kind = "ConfigMap" ServiceKind Kind = "Service" diff --git a/internal/delete/execute.go b/internal/delete/execute.go index 6d063ba..8d5eb64 100644 --- a/internal/delete/execute.go +++ b/internal/delete/execute.go @@ -27,10 +27,11 @@ import ( deletelocalcontrolplane "github.com/datasance/potctl/internal/delete/controlplane/local" deleteremotecontrolplane "github.com/datasance/potctl/internal/delete/controlplane/remote" deletemicroservice "github.com/datasance/potctl/internal/delete/microservice" + deletenatsaccountrule "github.com/datasance/potctl/internal/delete/natsaccountrule" + deletenatsuserrule "github.com/datasance/potctl/internal/delete/natsuserrule" deleteregistry "github.com/datasance/potctl/internal/delete/registry" deleterole "github.com/datasance/potctl/internal/delete/role" deleterolebinding "github.com/datasance/potctl/internal/delete/rolebinding" - deleteroute "github.com/datasance/potctl/internal/delete/route" deletesecret "github.com/datasance/potctl/internal/delete/secret" deleteservice "github.com/datasance/potctl/internal/delete/service" deleteserviceaccount "github.com/datasance/potctl/internal/delete/serviceaccount" @@ -48,7 +49,6 @@ type Options struct { var kindOrder = []config.Kind{ config.ServiceKind, - config.RouteKind, config.MicroserviceKind, config.ApplicationKind, config.CatalogItemKind, @@ -61,6 +61,8 @@ var kindOrder = []config.Kind{ config.ServiceAccountKind, config.RoleBindingKind, config.RoleKind, + config.NatsAccountRuleKind, + config.NatsUserRuleKind, config.CertificateKind, config.CertificateAuthorityKind, config.SecretKind, @@ -123,12 +125,15 @@ var kindHandlers = map[config.Kind]func(*execute.KindHandlerOpt) (execute.Execut config.ServiceAccountKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { return deleteserviceaccount.NewExecutor(opt.Namespace, opt.Name) }, + config.NatsAccountRuleKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { + return deletenatsaccountrule.NewExecutor(opt.Namespace, opt.Name) + }, + config.NatsUserRuleKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { + return deletenatsuserrule.NewExecutor(opt.Namespace, opt.Name) + }, config.ServiceKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { return deleteservice.NewExecutor(opt.Namespace, opt.Name) }, - config.RouteKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { - return deleteroute.NewExecutor(opt.Namespace, opt.Name), nil - }, config.VolumeMountKind: func(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { return deletevolumemount.NewExecutor(opt.Namespace, opt.Name) }, diff --git a/internal/delete/natsaccountrule/nats_account_rule.go b/internal/delete/natsaccountrule/nats_account_rule.go new file mode 100644 index 0000000..86a1ab3 --- /dev/null +++ b/internal/delete/natsaccountrule/nats_account_rule.go @@ -0,0 +1,32 @@ +package deletenatsaccountrule + +import ( + "github.com/datasance/potctl/internal/execute" + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" +) + +type Executor struct { + namespace string + name string +} + +func NewExecutor(namespace, name string) (execute.Executor, error) { + return &Executor{ + namespace: namespace, + name: name, + }, nil +} + +func (exe *Executor) GetName() string { + return exe.name +} + +func (exe *Executor) Execute() error { + util.SpinStart("Deleting NATS account rule") + clt, err := clientutil.NewControllerClient(exe.namespace) + if err != nil { + return err + } + return clt.DeleteNatsAccountRule(exe.name) +} diff --git a/internal/delete/natsuserrule/nats_user_rule.go b/internal/delete/natsuserrule/nats_user_rule.go new file mode 100644 index 0000000..813d601 --- /dev/null +++ b/internal/delete/natsuserrule/nats_user_rule.go @@ -0,0 +1,32 @@ +package deletenatsuserrule + +import ( + "github.com/datasance/potctl/internal/execute" + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" +) + +type Executor struct { + namespace string + name string +} + +func NewExecutor(namespace, name string) (execute.Executor, error) { + return &Executor{ + namespace: namespace, + name: name, + }, nil +} + +func (exe *Executor) GetName() string { + return exe.name +} + +func (exe *Executor) Execute() error { + util.SpinStart("Deleting NATS user rule") + clt, err := clientutil.NewControllerClient(exe.namespace) + if err != nil { + return err + } + return clt.DeleteNatsUserRule(exe.name) +} diff --git a/internal/delete/route/factory.go b/internal/delete/route/factory.go deleted file mode 100644 index 908401a..0000000 --- a/internal/delete/route/factory.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package deleteroute - -import ( - "github.com/datasance/potctl/internal/config" - "github.com/datasance/potctl/internal/execute" - clientutil "github.com/datasance/potctl/internal/util/client" -) - -type executor struct { - namespace string - name string -} - -func (exe executor) GetName() string { - return "deleting Route " + exe.name -} - -func (exe executor) Execute() (err error) { - if _, err = config.GetNamespace(exe.namespace); err != nil { - return - } - - // Connect to Controller - clt, err := clientutil.NewControllerClient(exe.namespace) - if err != nil { - return - } - - appName, routeName, err := clientutil.ParseFQName(exe.name, "Route") - if err != nil { - return err - } - - if err = clt.DeleteRoute(appName, routeName); err != nil { - return - } - return -} - -func NewExecutor(namespace, name string) (exe execute.Executor) { - return executor{ - namespace: namespace, - name: name, - } -} diff --git a/internal/deploy/agentconfig/utils.go b/internal/deploy/agentconfig/utils.go index 21b69a2..43f5bfe 100644 --- a/internal/deploy/agentconfig/utils.go +++ b/internal/deploy/agentconfig/utils.go @@ -28,6 +28,9 @@ const ( EdgeRouter RouterMode = "edge" InteriorRouter RouterMode = "interior" NoneRouter RouterMode = "none" + NatsNone string = "none" + NatsLeaf string = "leaf" + NatsServer string = "server" ) func getRouterMode(config *rsc.AgentConfiguration) RouterMode { @@ -56,6 +59,10 @@ func Validate(config *rsc.AgentConfiguration) error { msg := "agent config %s validation failed. Cannot have an edgeRouterPort or interRouterPort if routerMode is different from interior. Current router mode is: %s" return util.NewInputError(fmt.Sprintf(msg, config.Name, routerMode)) } + if config.NatsMode != nil && *config.NatsMode != NatsNone && *config.NatsMode != NatsLeaf && *config.NatsMode != NatsServer { + msg := "agent config %s validation failed. natsMode has to be one of none, leaf, server" + return util.NewInputError(fmt.Sprintf(msg, config.Name)) + } return nil } @@ -99,6 +106,19 @@ func Process(agentConfig *rsc.AgentConfiguration, name, agentIP string, otherAge } agentConfig.NetworkRouter = &uuid } + if agentConfig.UpstreamNatsServers != nil { + upstreamNatsServersUUID := []string{} + for _, agentName := range *agentConfig.UpstreamNatsServers { + uuid, err := findAgentUUIDInList(otherAgents, agentName) + if err != nil { + // Keep raw value for controller-reserved NATS hub aliases. + upstreamNatsServersUUID = append(upstreamNatsServersUUID, agentName) + continue + } + upstreamNatsServersUUID = append(upstreamNatsServersUUID, uuid) + } + agentConfig.UpstreamNatsServers = &upstreamNatsServersUUID + } if routerMode != NoneRouter && agentConfig.Host == nil { agentConfig.Host = &agentIP diff --git a/internal/deploy/edgeresource/factory.go b/internal/deploy/edgeresource/factory.go index 2947da5..785d233 100644 --- a/internal/deploy/edgeresource/factory.go +++ b/internal/deploy/edgeresource/factory.go @@ -11,7 +11,7 @@ * */ -package deployroute +package deployedgeresource import ( "github.com/datasance/iofog-go-sdk/v3/pkg/client" diff --git a/internal/deploy/execute.go b/internal/deploy/execute.go index 95b1b63..0a6d3b8 100644 --- a/internal/deploy/execute.go +++ b/internal/deploy/execute.go @@ -32,11 +32,12 @@ import ( deployremotecontrolplane "github.com/datasance/potctl/internal/deploy/controlplane/remote" deployedgeresource "github.com/datasance/potctl/internal/deploy/edgeresource" deploymicroservice "github.com/datasance/potctl/internal/deploy/microservice" + deploynatsaccountrule "github.com/datasance/potctl/internal/deploy/natsaccountrule" + deploynatsuserrule "github.com/datasance/potctl/internal/deploy/natsuserrule" deployofflineimage "github.com/datasance/potctl/internal/deploy/offlineimage" deployregistry "github.com/datasance/potctl/internal/deploy/registry" deployrole "github.com/datasance/potctl/internal/deploy/role" deployrolebinding "github.com/datasance/potctl/internal/deploy/rolebinding" - deployroute "github.com/datasance/potctl/internal/deploy/route" deploysecret "github.com/datasance/potctl/internal/deploy/secret" deployservice "github.com/datasance/potctl/internal/deploy/service" deployserviceaccount "github.com/datasance/potctl/internal/deploy/serviceaccount" @@ -58,6 +59,8 @@ var kindOrder = []config.Kind{ config.RoleKind, config.RoleBindingKind, config.ServiceAccountKind, + config.NatsAccountRuleKind, + config.NatsUserRuleKind, config.RemoteAgentKind, config.LocalAgentKind, config.EdgeResourceKind, @@ -69,7 +72,6 @@ var kindOrder = []config.Kind{ config.CatalogItemKind, config.ApplicationKind, config.MicroserviceKind, - config.RouteKind, config.ServiceKind, } @@ -140,10 +142,6 @@ func deployVolume(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) return deployvolume.NewExecutor(deployvolume.Options{Namespace: opt.Namespace, Yaml: opt.YAML, Name: opt.Name}) } -func deployRoute(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { - return deployroute.NewExecutor(deployroute.Options{Namespace: opt.Namespace, Yaml: opt.YAML, Name: opt.Name}) -} - func deploySecret(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { return deploysecret.NewExecutor(deploysecret.Options{Namespace: opt.Namespace, Yaml: opt.YAML, Data: opt.Data, Name: opt.Name}) } @@ -176,6 +174,24 @@ func deployServiceAccount(opt *execute.KindHandlerOpt) (exe execute.Executor, er return deployserviceaccount.NewExecutor(deployserviceaccount.Options{Namespace: opt.Namespace, Yaml: opt.YAML, Name: opt.Name}) } +func deployNatsAccountRule(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { + return deploynatsaccountrule.NewExecutor(deploynatsaccountrule.Options{ + Namespace: opt.Namespace, + Yaml: opt.YAML, + FullYAML: opt.FullYAML, + Name: opt.Name, + }) +} + +func deployNatsUserRule(opt *execute.KindHandlerOpt) (exe execute.Executor, err error) { + return deploynatsuserrule.NewExecutor(deploynatsuserrule.Options{ + Namespace: opt.Namespace, + Yaml: opt.YAML, + FullYAML: opt.FullYAML, + Name: opt.Name, + }) +} + // Execute deploy from yaml file func Execute(opt *Options) (err error) { kindHandlers := buildKindHandlers(opt.NoCache, opt.TransferPool) @@ -234,17 +250,31 @@ func Execute(opt *Options) (err error) { routerMode := iofog.RouterModeInterior edgeRouterPort := 45671 interRouterPort := 55671 + upstreamNatsServers := []string{} + natsMode := iofog.NatsModeServer + natsServerPort := 4222 + natsLeafPort := 7422 + natsClusterPort := 6222 + natsMqttPort := 8883 + natsHttpPort := 8222 agentConfig.IsSystem = &isSystem agentConfig.DeploymentType = &deploymentType agentConfig.UpstreamRouters = &upstreamRouters + agentConfig.UpstreamNatsServers = &upstreamNatsServers agentConfig.RouterConfig = client.RouterConfig{ RouterMode: &routerMode, EdgeRouterPort: &edgeRouterPort, InterRouterPort: &interRouterPort, } + agentConfig.NatsMode = &natsMode + agentConfig.NatsServerPort = &natsServerPort + agentConfig.NatsLeafPort = &natsLeafPort + agentConfig.NatsClusterPort = &natsClusterPort + agentConfig.NatsMqttPort = &natsMqttPort + agentConfig.NatsHttpPort = &natsHttpPort } else { // For remote agents, use the configuration from the agent executor - if deployConfig == nil || deployConfig.AgentConfiguration == (client.AgentConfiguration{}) { + if deployConfig == nil { // Initialize default remote agent configuration agentConfig = client.AgentConfiguration{ Host: &host, @@ -331,12 +361,13 @@ func buildKindHandlers(noCache bool, transferPool int) map[config.Kind]func(*exe config.AgentConfigKind: deployAgentConfig, config.RegistryKind: deployRegistry, config.VolumeKind: deployVolume, - config.RouteKind: deployRoute, config.SecretKind: deploySecret, config.ConfigMapKind: deployConfigMap, config.RoleKind: deployRole, config.RoleBindingKind: deployRoleBinding, config.ServiceAccountKind: deployServiceAccount, + config.NatsAccountRuleKind: deployNatsAccountRule, + config.NatsUserRuleKind: deployNatsUserRule, config.ServiceKind: deployService, config.VolumeMountKind: deployVolumeMount, config.CertificateAuthorityKind: deployCertificate, @@ -424,7 +455,7 @@ func sortAndExecute(namespace string, executors []deployagentconfig.AgentConfigE } // Set dependencies for agent config topological sort configuration := agentConfigExecutor.GetConfiguration() - dependencies := getDependencies(configuration.UpstreamRouters, configuration.NetworkRouter) + dependencies := getDependencies(configuration.UpstreamRouters, configuration.NetworkRouter, configuration.UpstreamNatsServers) if err := makeEdges(g, node, nodeMap, agentNodeMap, agentByName, agentByUUID, dependencies); err != nil { return err } @@ -479,7 +510,7 @@ func makeEdges(g *graph.Graph, node graph.Node, nodeMap, agentNodeMap map[string } if agent != nil { // Fill dependency graph with agents on Controller - uuidDependencies := getDependencies(agent.UpstreamRouters, agent.NetworkRouter) + uuidDependencies := getDependencies(agent.UpstreamRouters, agent.NetworkRouter, agent.UpstreamNatsServers) if err := makeEdges(g, dependsOnNode, nodeMap, agentNodeMap, agentByName, agentByUUID, mapUUIDsToNames(uuidDependencies, agentByUUID)); err != nil { return err } @@ -493,7 +524,7 @@ func makeEdges(g *graph.Graph, node graph.Node, nodeMap, agentNodeMap map[string return nil } -func getDependencies(upstreamRouters *[]string, networkRouter *string) []string { +func getDependencies(upstreamRouters *[]string, networkRouter *string, upstreamNatsServers *[]string) []string { dependencies := []string{} if upstreamRouters != nil { dependencies = append(dependencies, *upstreamRouters...) @@ -501,6 +532,9 @@ func getDependencies(upstreamRouters *[]string, networkRouter *string) []string if networkRouter != nil { dependencies = append(dependencies, *networkRouter) } + if upstreamNatsServers != nil { + dependencies = append(dependencies, *upstreamNatsServers...) + } return dependencies } diff --git a/internal/deploy/natsaccountrule/factory.go b/internal/deploy/natsaccountrule/factory.go new file mode 100644 index 0000000..52f0e54 --- /dev/null +++ b/internal/deploy/natsaccountrule/factory.go @@ -0,0 +1,81 @@ +package deploynatsaccountrule + +import ( + "bytes" + "fmt" + + "github.com/datasance/iofog-go-sdk/v3/pkg/client" + "github.com/datasance/potctl/internal/config" + "github.com/datasance/potctl/internal/execute" + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "gopkg.in/yaml.v2" +) + +type Options struct { + Namespace string + Yaml []byte + FullYAML []byte + Name string +} + +type executor struct { + namespace string + name string + fullYAML []byte +} + +func (exe *executor) GetName() string { + return exe.name +} + +func (exe *executor) Execute() error { + util.SpinStart(fmt.Sprintf("Deploying NATS account rule %s", exe.GetName())) + clt, err := clientutil.NewControllerClient(exe.namespace) + if err != nil { + return err + } + + reader := bytes.NewReader(exe.fullYAML) + _, err = clt.UpdateNatsAccountRuleFromYAML(exe.name, reader) + if err == nil { + return nil + } + if _, ok := err.(*client.NotFoundError); !ok { + return err + } + + reader = bytes.NewReader(exe.fullYAML) + _, err = clt.CreateNatsAccountRuleFromYAML(reader) + return err +} + +func NewExecutor(opt Options) (execute.Executor, error) { + ns, err := config.GetNamespace(opt.Namespace) + if err != nil { + return nil, err + } + controlPlane, err := ns.GetControlPlane() + if err != nil { + return nil, err + } + if len(controlPlane.GetControllers()) == 0 { + return nil, util.NewInputError("This namespace does not have a Controller. You must first deploy a Controller before deploying NATS account rules") + } + + // Validate YAML shape using strict decode against expected top-level fields. + var validateDoc struct { + Kind config.Kind `yaml:"kind"` + Metadata config.HeaderMetadata `yaml:"metadata"` + Spec map[string]interface{} `yaml:"spec"` + } + if err = yaml.UnmarshalStrict(opt.FullYAML, &validateDoc); err != nil { + return nil, util.NewUnmarshalError(err.Error()) + } + + return &executor{ + namespace: opt.Namespace, + name: opt.Name, + fullYAML: opt.FullYAML, + }, nil +} diff --git a/internal/deploy/natsuserrule/factory.go b/internal/deploy/natsuserrule/factory.go new file mode 100644 index 0000000..47cefe3 --- /dev/null +++ b/internal/deploy/natsuserrule/factory.go @@ -0,0 +1,81 @@ +package deploynatsuserrule + +import ( + "bytes" + "fmt" + + "github.com/datasance/iofog-go-sdk/v3/pkg/client" + "github.com/datasance/potctl/internal/config" + "github.com/datasance/potctl/internal/execute" + clientutil "github.com/datasance/potctl/internal/util/client" + "github.com/datasance/potctl/pkg/util" + "gopkg.in/yaml.v2" +) + +type Options struct { + Namespace string + Yaml []byte + FullYAML []byte + Name string +} + +type executor struct { + namespace string + name string + fullYAML []byte +} + +func (exe *executor) GetName() string { + return exe.name +} + +func (exe *executor) Execute() error { + util.SpinStart(fmt.Sprintf("Deploying NATS user rule %s", exe.GetName())) + clt, err := clientutil.NewControllerClient(exe.namespace) + if err != nil { + return err + } + + reader := bytes.NewReader(exe.fullYAML) + _, err = clt.UpdateNatsUserRuleFromYAML(exe.name, reader) + if err == nil { + return nil + } + if _, ok := err.(*client.NotFoundError); !ok { + return err + } + + reader = bytes.NewReader(exe.fullYAML) + _, err = clt.CreateNatsUserRuleFromYAML(reader) + return err +} + +func NewExecutor(opt Options) (execute.Executor, error) { + ns, err := config.GetNamespace(opt.Namespace) + if err != nil { + return nil, err + } + controlPlane, err := ns.GetControlPlane() + if err != nil { + return nil, err + } + if len(controlPlane.GetControllers()) == 0 { + return nil, util.NewInputError("This namespace does not have a Controller. You must first deploy a Controller before deploying NATS user rules") + } + + // Validate YAML shape using strict decode against expected top-level fields. + var validateDoc struct { + Kind config.Kind `yaml:"kind"` + Metadata config.HeaderMetadata `yaml:"metadata"` + Spec map[string]interface{} `yaml:"spec"` + } + if err = yaml.UnmarshalStrict(opt.FullYAML, &validateDoc); err != nil { + return nil, util.NewUnmarshalError(err.Error()) + } + + return &executor{ + namespace: opt.Namespace, + name: opt.Name, + fullYAML: opt.FullYAML, + }, nil +} diff --git a/internal/deploy/route/factory.go b/internal/deploy/route/factory.go deleted file mode 100644 index c11db10..0000000 --- a/internal/deploy/route/factory.go +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package deployroute - -import ( - "fmt" - - "github.com/datasance/iofog-go-sdk/v3/pkg/client" - "github.com/datasance/potctl/internal/config" - "github.com/datasance/potctl/internal/execute" - rsc "github.com/datasance/potctl/internal/resource" - clientutil "github.com/datasance/potctl/internal/util/client" - "github.com/datasance/potctl/pkg/util" - yaml "gopkg.in/yaml.v2" -) - -type Options struct { - Namespace string - Name string - Yaml []byte -} - -type executor struct { - namespace string - name string - appName string - route rsc.Route -} - -func (exe *executor) GetName() string { - return "deploying Route " + exe.name -} - -func (exe *executor) Execute() (err error) { - if _, err = config.GetNamespace(exe.namespace); err != nil { - return - } - - // Connect to Controller - clt, err := clientutil.NewControllerClient(exe.namespace) - if err != nil { - return - } - - if err = clt.UpdateRoute(&client.Route{ - Name: exe.name, - From: exe.route.From, - To: exe.route.To, - Application: exe.appName, - }); err != nil { - return - } - return -} - -func NewExecutor(opt Options) (execute.Executor, error) { - // Unmarshal file - var route rsc.Route - if err := yaml.UnmarshalStrict(opt.Yaml, &route); err != nil { - err = util.NewUnmarshalError(err.Error()) - return nil, err - } - // Validate input - if route.Name == "" && opt.Name == "" { - return nil, util.NewInputError("Did not specify metadata.name or spec.name") - } - - appName, routeName, err := clientutil.ParseFQName(opt.Name, "Route") - if err != nil { - return nil, err - } - - if route.Name == "" { - route.Name = routeName - } - - if route.Name != routeName { - return nil, util.NewInputError(fmt.Sprintf("Mismatch between metadata.name [%s] and spec.name [%s]", opt.Name, route.Name)) - } - - return &executor{ - namespace: opt.Namespace, - name: routeName, - appName: appName, - route: route, - }, nil -} diff --git a/internal/describe/application.go b/internal/describe/application.go index f517775..7d913b2 100644 --- a/internal/describe/application.go +++ b/internal/describe/application.go @@ -14,8 +14,7 @@ package describe import ( - "fmt" - + apps "github.com/datasance/iofog-go-sdk/v3/pkg/apps" "github.com/datasance/iofog-go-sdk/v3/pkg/client" "github.com/datasance/potctl/internal/config" rsc "github.com/datasance/potctl/internal/resource" @@ -30,8 +29,8 @@ type applicationExecutor struct { flow *client.FlowInfo client *client.Client msvcs []*client.MicroserviceInfo - routes []client.Route msvcPerID map[string]*client.MicroserviceInfo + natsCfg *client.ApplicationNatsConfig } func newApplicationExecutor(namespace, name, filename string) *applicationExecutor { @@ -48,12 +47,6 @@ func (exe *applicationExecutor) init() (err error) { return } - routeList, err := exe.client.ListRoutes() - if err != nil { - return err - } - exe.routes = routeList.Routes - application, err := exe.client.GetApplicationByName(exe.name) // If not found error, try legacy if _, ok := err.(*client.NotFoundError); ok { @@ -72,6 +65,7 @@ func (exe *applicationExecutor) init() (err error) { UserID: application.UserID, ID: application.ID, } + exe.natsCfg = application.NatsConfig msvcListResponse, err := exe.client.GetMicroservicesByApplication(exe.name) if err != nil { return err @@ -89,7 +83,6 @@ func (exe *applicationExecutor) init() (err error) { for i := 0; i < len(exe.msvcs); i++ { exe.msvcPerID[exe.msvcs[i].UUID] = exe.msvcs[i] } - return err } @@ -104,8 +97,7 @@ func (exe *applicationExecutor) Execute() error { } yamlMsvcs := []rsc.Microservice{} - yamlRoutes := []rsc.Route{} - + var natsCfg *apps.ApplicationNatsConfig for idx := range exe.msvcs { yamlMsvc, _, _, err := MapClientMicroserviceToDeployMicroservice(exe.msvcs[idx], exe.client) if err != nil { @@ -115,26 +107,17 @@ func (exe *applicationExecutor) Execute() error { yamlMsvc.Flow = nil yamlMsvcs = append(yamlMsvcs, *yamlMsvc) } - - for _, route := range exe.routes { - from, okSrc := exe.msvcPerID[route.From] - to, okDest := exe.msvcPerID[route.To] - if okSrc { - if !okDest { - return util.NewNotFoundError(fmt.Sprintf("Route %s contains a destination microservice that could not be found in the application", route.Name)) - } - yamlRoutes = append(yamlRoutes, rsc.Route{ - Name: route.Name, - From: from.Name, - To: to.Name, - }) + if exe.natsCfg != nil { + natsCfg = &apps.ApplicationNatsConfig{ + NatsAccess: exe.natsCfg.NatsAccess, + NatsRule: exe.natsCfg.NatsRule, } } application := rsc.Application{ Name: exe.flow.Name, Microservices: yamlMsvcs, - Routes: yamlRoutes, + NatsConfig: natsCfg, ID: exe.flow.ID, } diff --git a/internal/describe/factory.go b/internal/describe/factory.go index 1ae88be..f851433 100644 --- a/internal/describe/factory.go +++ b/internal/describe/factory.go @@ -53,8 +53,6 @@ func NewExecutor(opt *Options) (execute.Executor, error) { return newApplicationExecutor(opt.Namespace, opt.Name, opt.Filename), nil case "volume": return newVolumeExecutor(opt.Namespace, opt.Name, opt.Filename), nil - case "route": - return newRouteExecutor(opt.Namespace, opt.Name, opt.Filename), nil case "edge-resource": return newEdgeResourceExecutor(opt.Namespace, opt.Name, opt.Version, opt.Filename), nil case "secret": diff --git a/internal/describe/route.go b/internal/describe/route.go deleted file mode 100644 index 1eb12c8..0000000 --- a/internal/describe/route.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package describe - -import ( - "github.com/datasance/potctl/internal/config" - rsc "github.com/datasance/potctl/internal/resource" - clientutil "github.com/datasance/potctl/internal/util/client" - "github.com/datasance/potctl/pkg/util" -) - -type routeExecutor struct { - namespace string - name string - filename string -} - -func newRouteExecutor(namespace, name, filename string) *routeExecutor { - return &routeExecutor{ - namespace: namespace, - name: name, - filename: filename, - } -} - -func (exe *routeExecutor) GetName() string { - return exe.name -} - -func (exe *routeExecutor) Execute() error { - _, err := config.GetNamespace(exe.namespace) - if err != nil { - return err - } - - // Connect to Controller - clt, err := clientutil.NewControllerClient(exe.namespace) - if err != nil { - return err - } - - appName, routeName, err := clientutil.ParseFQName(exe.name, "Route") - if err != nil { - return err - } - - // Get Route - route, err := clt.GetRoute(appName, routeName) - if err != nil { - return err - } - - // Convert route details - from, err := clientutil.GetMicroserviceName(exe.namespace, appName, route.From) - if err != nil { - return err - } - to, err := clientutil.GetMicroserviceName(exe.namespace, appName, route.To) - if err != nil { - return err - } - - // Convert to YAML - header := config.Header{ - APIVersion: config.LatestAPIVersion, - Kind: config.RouteKind, - Metadata: config.HeaderMetadata{ - Namespace: exe.namespace, - Name: exe.name, - }, - Spec: rsc.Route{ - From: from, - To: to, - Name: routeName, - }, - } - - if exe.filename == "" { - if err := util.Print(header); err != nil { - return err - } - } else { - if err := util.FPrint(header, exe.filename); err != nil { - return err - } - } - return nil -} diff --git a/internal/describe/utils.go b/internal/describe/utils.go index b3dc77b..2eb073a 100644 --- a/internal/describe/utils.go +++ b/internal/describe/utils.go @@ -17,8 +17,6 @@ import ( "fmt" "time" - jsoniter "github.com/json-iterator/go" - apps "github.com/datasance/iofog-go-sdk/v3/pkg/apps" "github.com/datasance/iofog-go-sdk/v3/pkg/client" rsc "github.com/datasance/potctl/internal/resource" @@ -175,14 +173,6 @@ func constructMicroservice(msvcInfo *client.MicroserviceInfo, agentName, appName envs := mapEnvs(msvcInfo.Env) extraHosts := mapExtraHosts(msvcInfo.ExtraHosts) msvc.Images = &images - jsonConfig := make(map[string]interface{}) - if err := jsoniter.Unmarshal([]byte(msvcInfo.Config), &jsonConfig); err != nil { - return msvc, nil, nil, err - } - jsonAnnotations := make(map[string]interface{}) - if err := jsoniter.Unmarshal([]byte(msvcInfo.Annotations), &jsonAnnotations); err != nil { - return msvc, nil, nil, err - } var healthCheck apps.MicroserviceHealthCheck var hasHealthCheck bool // Fix 1: Check if HealthCheck has a Test field (assuming it's a struct, not pointer) @@ -210,8 +200,16 @@ func constructMicroservice(msvcInfo *client.MicroserviceInfo, agentName, appName healthCheck.StartInterval = msvcInfo.HealthCheck.StartInterval } } - msvc.Config = jsonConfig - msvc.Container.Annotations = jsonAnnotations + var config apps.ArbitraryJSON + if err := config.UnmarshalJSON([]byte(msvcInfo.Config)); err != nil { + return msvc, nil, nil, err + } + msvc.Config = config + var annotations apps.ArbitraryJSON + if err := annotations.UnmarshalJSON([]byte(msvcInfo.Annotations)); err != nil { + return msvc, nil, nil, err + } + msvc.Container.Annotations = annotations msvc.Container.HostNetworkMode = msvcInfo.HostNetworkMode msvc.Container.IsPrivileged = msvcInfo.IsPrivileged msvc.Container.PidMode = msvcInfo.PidMode @@ -232,9 +230,11 @@ func constructMicroservice(msvcInfo *client.MicroserviceInfo, agentName, appName if hasHealthCheck { msvc.Container.HealthCheck = &healthCheck } - msvc.MsRoutes = apps.MsRoutes{ - PubTags: msvcInfo.PubTags, - SubTags: msvcInfo.SubTags, + if msvcInfo.NatsConfig != nil { + msvc.NatsConfig = &apps.MicroserviceNatsConfig{ + NatsAccess: msvcInfo.NatsConfig.NatsAccess, + NatsRule: msvcInfo.NatsConfig.NatsRule, + } } msvc.Schedule = msvcInfo.Schedule msvc.Application = &appName diff --git a/internal/exec/agent.go b/internal/exec/agent.go index d42921e..0be1ad1 100644 --- a/internal/exec/agent.go +++ b/internal/exec/agent.go @@ -58,8 +58,8 @@ func (exe *agentExecutor) Execute() error { return fmt.Errorf(msg, err.Error()) } - appName := fmt.Sprintf("system-%s", agent.UUID) - msvcName := fmt.Sprintf("debug-%s", agent.UUID) + appName := fmt.Sprintf("system-%s", agent.Name) + msvcName := fmt.Sprintf("debug-%s", agent.Name) exe.msvc, err = clt.GetMicroserviceByName(appName, msvcName) if err != nil { diff --git a/internal/execute/utils.go b/internal/execute/utils.go index bc19658..7adbea8 100644 --- a/internal/execute/utils.go +++ b/internal/execute/utils.go @@ -79,6 +79,10 @@ func generateExecutor(header *config.Header, namespace string, kindHandlers map[ if err != nil { return exe, err } + fullYamlBytes, err := yaml.Marshal(header) + if err != nil { + return exe, err + } createExecutorFunc, found := kindHandlers[header.Kind] if !found { @@ -91,6 +95,7 @@ func generateExecutor(header *config.Header, namespace string, kindHandlers map[ Namespace: namespace, Name: header.Metadata.Name, YAML: subYamlBytes, + FullYAML: fullYamlBytes, Data: dataYamlBytes, Tags: header.Metadata.Tags, }) @@ -101,6 +106,7 @@ type KindHandlerOpt struct { Namespace string Name string YAML []byte + FullYAML []byte Data []byte Tags *[]string } @@ -137,7 +143,7 @@ func GetExecutorsFromYAML(inputFile, namespace string, kindHandlers map[config.K decodeErr = dec.Decode(&h) } - if decodeErr != io.EOF && decodeErr != nil { + if decodeErr != io.EOF { return nil, decodeErr } diff --git a/internal/get/all.go b/internal/get/all.go index 61f857d..96084b8 100644 --- a/internal/get/all.go +++ b/internal/get/all.go @@ -27,7 +27,6 @@ var ( getApplicationTable, getSystemApplicationTable, getVolumeTable, - getRouteTable, getServiceTable, getVolumeMountTable, } @@ -137,14 +136,6 @@ func getVolumeTable(namespace string, tableChan tableChannel) { } } -func getRouteTable(namespace string, tableChan tableChannel) { - table, err := generateRouteOutput(namespace) - tableChan <- tableQuery{ - table: table, - err: err, - } -} - func getEdgeResourceTable(namespace string, tableChan tableChannel) { table, err := generateEdgeResourceOutput(namespace) tableChan <- tableQuery{ diff --git a/internal/get/applications.go b/internal/get/applications.go index 7938497..8be7988 100644 --- a/internal/get/applications.go +++ b/internal/get/applications.go @@ -27,12 +27,14 @@ type applicationExecutor struct { client *client.Client flows []client.FlowInfo msvcsPerApplication map[int][]*client.MicroserviceInfo + natsPerApplication map[int]*client.ApplicationNatsConfig } func newApplicationExecutor(namespace string) *applicationExecutor { c := &applicationExecutor{} c.namespace = namespace c.msvcsPerApplication = make(map[int][]*client.MicroserviceInfo) + c.natsPerApplication = make(map[int]*client.ApplicationNatsConfig) return c } @@ -84,6 +86,7 @@ func (exe *applicationExecutor) init() (err error) { UserID: application.UserID, ID: application.ID, }) + exe.natsPerApplication[application.ID] = application.NatsConfig listMsvcs, err := exe.client.GetMicroservicesByApplication(application.Name) if err != nil { return err @@ -104,7 +107,7 @@ func (exe *applicationExecutor) init() (err error) { func (exe *applicationExecutor) generateApplicationOutput() (table [][]string) { // Generate table and headers table = make([][]string, len(exe.flows)+1) - headers := []string{"APPLICATION", "RUNNING", "MICROSERVICES"} + headers := []string{"APPLICATION", "RUNNING", "NATS ACCESS", "MICROSERVICES"} table[0] = append(table[0], headers...) // Populate rows @@ -131,10 +134,15 @@ func (exe *applicationExecutor) generateApplicationOutput() (table [][]string) { } status := fmt.Sprintf("%d/%d", runningMsvcs, nbMsvcs) + natsAccess := "false" + if natsConfig := exe.natsPerApplication[flow.ID]; natsConfig != nil && natsConfig.NatsAccess { + natsAccess = "true" + } row := []string{ flow.Name, status, + natsAccess, msvcs, } table[idx+1] = append(table[idx+1], row...) diff --git a/internal/get/factory.go b/internal/get/factory.go index 113900b..e7fcfe5 100644 --- a/internal/get/factory.go +++ b/internal/get/factory.go @@ -44,8 +44,6 @@ func NewExecutor(resourceType, namespace string, showDetached bool) (execute.Exe return newRegistryExecutor(namespace), nil case "volumes": return newVolumeExecutor(namespace), nil - case "routes": - return newRouteExecutor(namespace), nil case "edge-resources": return newEdgeResourceExecutor(namespace), nil case "secrets": @@ -64,6 +62,14 @@ func NewExecutor(resourceType, namespace string, showDetached bool) (execute.Exe return newRoleBindingExecutor(namespace), nil case "serviceaccounts": return newServiceAccountExecutor(namespace), nil + case "nats-accounts": + return newNatsAccountExecutor(namespace), nil + case "nats-users": + return newNatsUserExecutor(namespace), nil + case "nats-account-rules": + return newNatsAccountRuleExecutor(namespace), nil + case "nats-user-rules": + return newNatsUserRuleExecutor(namespace), nil default: msg := "Unknown resource: '" + resourceType + "'" return nil, util.NewInputError(msg) diff --git a/internal/get/microservices.go b/internal/get/microservices.go index 377f91e..9193f9a 100644 --- a/internal/get/microservices.go +++ b/internal/get/microservices.go @@ -82,7 +82,7 @@ func (exe *microserviceExecutor) Execute() error { func (exe *microserviceExecutor) generateMicroserviceOutput() (table [][]string) { // Generate table and headers table = make([][]string, len(exe.msvcPerID)+1) - headers := []string{"MICROSERVICE", "STATUS", "AGENT", "VOLUMES", "PORTS"} + headers := []string{"MICROSERVICE", "STATUS", "AGENT", "NATS ACCESS", "VOLUMES", "PORTS"} table[0] = append(table[0], headers...) // Populate rows @@ -133,11 +133,16 @@ func (exe *microserviceExecutor) generateMicroserviceOutput() (table [][]string) } status = fmt.Sprintf("%s (%s)", ms.Status.Status, msg) } + natsAccess := "false" + if ms.NatsConfig != nil && ms.NatsConfig.NatsAccess { + natsAccess = "true" + } row := []string{ ms.Name, status, agentName, + natsAccess, volumes, ports, } diff --git a/internal/get/nats_account_rules.go b/internal/get/nats_account_rules.go new file mode 100644 index 0000000..15deb07 --- /dev/null +++ b/internal/get/nats_account_rules.go @@ -0,0 +1,41 @@ +package get + +import clientutil "github.com/datasance/potctl/internal/util/client" + +type natsAccountRuleExecutor struct { + namespace string +} + +func newNatsAccountRuleExecutor(namespace string) *natsAccountRuleExecutor { + return &natsAccountRuleExecutor{namespace: namespace} +} + +func (exe *natsAccountRuleExecutor) GetName() string { return "" } + +func (exe *natsAccountRuleExecutor) Execute() error { + printNamespace(exe.namespace) + table, err := generateNatsAccountRulesOutput(exe.namespace) + if err != nil { + return err + } + return print(table) +} + +func generateNatsAccountRulesOutput(namespace string) ([][]string, error) { + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, err + } + + response, err := clt.ListNatsAccountRules() + if err != nil { + return nil, err + } + + table := make([][]string, len(response.Rules)+1) + table[0] = []string{"NAME"} + for idx, rule := range response.Rules { + table[idx+1] = []string{rule.Name} + } + return table, nil +} diff --git a/internal/get/nats_accounts.go b/internal/get/nats_accounts.go new file mode 100644 index 0000000..38cb233 --- /dev/null +++ b/internal/get/nats_accounts.go @@ -0,0 +1,50 @@ +package get + +import ( + "fmt" + + clientutil "github.com/datasance/potctl/internal/util/client" +) + +type natsAccountExecutor struct { + namespace string +} + +func newNatsAccountExecutor(namespace string) *natsAccountExecutor { + return &natsAccountExecutor{namespace: namespace} +} + +func (exe *natsAccountExecutor) GetName() string { return "" } + +func (exe *natsAccountExecutor) Execute() error { + printNamespace(exe.namespace) + table, err := generateNatsAccountsOutput(exe.namespace) + if err != nil { + return err + } + return print(table) +} + +func generateNatsAccountsOutput(namespace string) ([][]string, error) { + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, err + } + + response, err := clt.ListNatsAccounts() + if err != nil { + return nil, err + } + + table := make([][]string, len(response.Accounts)+1) + table[0] = []string{"NAME", "APP ID", "SYSTEM", "PUBLIC KEY"} + for idx, account := range response.Accounts { + table[idx+1] = []string{ + account.Name, + fmt.Sprintf("%d", account.ApplicationID), + fmt.Sprintf("%t", account.IsSystem), + account.PublicKey, + } + } + return table, nil +} diff --git a/internal/get/nats_user_rules.go b/internal/get/nats_user_rules.go new file mode 100644 index 0000000..c60b64e --- /dev/null +++ b/internal/get/nats_user_rules.go @@ -0,0 +1,41 @@ +package get + +import clientutil "github.com/datasance/potctl/internal/util/client" + +type natsUserRuleExecutor struct { + namespace string +} + +func newNatsUserRuleExecutor(namespace string) *natsUserRuleExecutor { + return &natsUserRuleExecutor{namespace: namespace} +} + +func (exe *natsUserRuleExecutor) GetName() string { return "" } + +func (exe *natsUserRuleExecutor) Execute() error { + printNamespace(exe.namespace) + table, err := generateNatsUserRulesOutput(exe.namespace) + if err != nil { + return err + } + return print(table) +} + +func generateNatsUserRulesOutput(namespace string) ([][]string, error) { + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, err + } + + response, err := clt.ListNatsUserRules() + if err != nil { + return nil, err + } + + table := make([][]string, len(response.Rules)+1) + table[0] = []string{"NAME"} + for idx, rule := range response.Rules { + table[idx+1] = []string{rule.Name} + } + return table, nil +} diff --git a/internal/get/nats_users.go b/internal/get/nats_users.go new file mode 100644 index 0000000..ba687a4 --- /dev/null +++ b/internal/get/nats_users.go @@ -0,0 +1,51 @@ +package get + +import ( + "fmt" + + clientutil "github.com/datasance/potctl/internal/util/client" +) + +type natsUserExecutor struct { + namespace string +} + +func newNatsUserExecutor(namespace string) *natsUserExecutor { + return &natsUserExecutor{namespace: namespace} +} + +func (exe *natsUserExecutor) GetName() string { return "" } + +func (exe *natsUserExecutor) Execute() error { + printNamespace(exe.namespace) + table, err := generateNatsUsersOutput(exe.namespace) + if err != nil { + return err + } + return print(table) +} + +func generateNatsUsersOutput(namespace string) ([][]string, error) { + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, err + } + + response, err := clt.ListNatsUsers() + if err != nil { + return nil, err + } + + table := make([][]string, len(response.Users)+1) + table[0] = []string{"NAME", "ACCOUNT", "APP", "BEARER", "PUBLIC KEY"} + for idx, user := range response.Users { + table[idx+1] = []string{ + user.Name, + user.AccountName, + user.ApplicationName, + fmt.Sprintf("%t", user.IsBearer), + user.PublicKey, + } + } + return table, nil +} diff --git a/internal/get/routes.go b/internal/get/routes.go deleted file mode 100644 index 20bd8d5..0000000 --- a/internal/get/routes.go +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package get - -import ( - "github.com/datasance/iofog-go-sdk/v3/pkg/client" - "github.com/datasance/potctl/internal/config" - rsc "github.com/datasance/potctl/internal/resource" - clientutil "github.com/datasance/potctl/internal/util/client" -) - -type routeExecutor struct { - namespace string -} - -func newRouteExecutor(namespace string) *routeExecutor { - return &routeExecutor{ - namespace: namespace, - } -} - -func (exe *routeExecutor) GetName() string { - return "" -} - -func (exe *routeExecutor) Execute() error { - printNamespace(exe.namespace) - table, err := generateRouteOutput(exe.namespace) - if err != nil { - return err - } - return print(table) -} - -func generateRouteOutput(namespace string) (table [][]string, err error) { - _, err = config.GetNamespace(namespace) - if err != nil { - return - } - - // Connect to Controller - clt, err := clientutil.NewControllerClient(namespace) - if err != nil && !rsc.IsNoControlPlaneError(err) { - return - } - - routes := []client.Route{} - if err == nil { - // Populate table - listResponse, err := clt.ListRoutes() - if err != nil { - return table, err - } - routes = listResponse.Routes - } - - return tabulateRoutes(namespace, routes) -} - -func tabulateRoutes(namespace string, routes []client.Route) (table [][]string, err error) { - // Generate table and headers - table = make([][]string, len(routes)+1) - headers := []string{"ROUTE", "SOURCE MSVC", "DEST MSVC"} - table[0] = append(table[0], headers...) - - // Populate rows - for idx, route := range routes { - // Convert route details - from, err := clientutil.GetMicroserviceName(namespace, route.Application, route.From) - if err != nil { - return table, err - } - to, err := clientutil.GetMicroserviceName(namespace, route.Application, route.To) - if err != nil { - return table, err - } - // Store values - row := []string{ - route.Name, - from, - to, - } - table[idx+1] = append(table[idx+1], row...) - } - return -} diff --git a/internal/get/templates.go b/internal/get/templates.go index 1a9b9fd..a4bb750 100644 --- a/internal/get/templates.go +++ b/internal/get/templates.go @@ -69,16 +69,24 @@ func (exe *applicationTemplateExecutor) init() (err error) { func (exe *applicationTemplateExecutor) generateApplicationTemplateOutput() (table [][]string) { // Generate table and headers table = make([][]string, len(exe.templates)+1) - headers := []string{"TEMPLATE", "DESCRIPTION", "MICROSERVICES", "ROUTES"} + headers := []string{"TEMPLATE", "DESCRIPTION", "MICROSERVICES", "NATS ACCESS"} table[0] = append(table[0], headers...) // Populate rows for idx, template := range exe.templates { + microserviceCount := 0 + if template.Application != nil { + microserviceCount = len(template.Application.Microservices) + } + natsAccess := "false" + if template.Application != nil && template.Application.NatsConfig != nil && template.Application.NatsConfig.NatsAccess { + natsAccess = "true" + } row := []string{ template.Name, template.Description, - strconv.Itoa(len(template.Application.Microservices)), - strconv.Itoa(len(template.Application.Routes)), + strconv.Itoa(microserviceCount), + natsAccess, } table[idx+1] = append(table[idx+1], row...) } diff --git a/internal/rename/route/executor.go b/internal/rename/route/executor.go deleted file mode 100644 index 336fe06..0000000 --- a/internal/rename/route/executor.go +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ******************************************************************************* - * * Copyright (c) 2023 Datasance Teknoloji A.S. - * * - * * This program and the accompanying materials are made available under the - * * terms of the Eclipse Public License v. 2.0 which is available at - * * http://www.eclipse.org/legal/epl-2.0 - * * - * * SPDX-License-Identifier: EPL-2.0 - * ******************************************************************************* - * - */ - -package route - -import ( - "fmt" - - clientutil "github.com/datasance/potctl/internal/util/client" - "github.com/datasance/potctl/pkg/util" -) - -func Execute(namespace, name, newName string) error { - // Init remote resources - clt, err := clientutil.NewControllerClient(namespace) - if err != nil { - return err - } - - appName, routeName, err := clientutil.ParseFQName(name, "Route") - if err != nil { - return err - } - - route, err := clt.GetRoute(appName, routeName) - if err != nil { - return err - } - - if err := util.IsLowerAlphanumeric("Route", newName); err != nil { - return err - } - util.SpinStart(fmt.Sprintf("Renaming route %s", name)) - route.Name = newName - // Temporary fix - route.From = "" - route.To = "" - - if err := clt.PatchRoute(appName, routeName, &route); err != nil { - return err - } - - return err -} diff --git a/internal/resource/types.go b/internal/resource/types.go index 67c079f..29de6b9 100644 --- a/internal/resource/types.go +++ b/internal/resource/types.go @@ -20,7 +20,6 @@ import ( "github.com/datasance/iofog-go-sdk/v3/pkg/client" ) -type Route = apps.Route type Microservice = apps.Microservice type Application = apps.Application type ApplicationTemplate = apps.ApplicationTemplate diff --git a/internal/util/client/api.go b/internal/util/client/api.go index e2669ff..60081e4 100644 --- a/internal/util/client/api.go +++ b/internal/util/client/api.go @@ -242,6 +242,15 @@ func GetAgentConfig(agentName, namespace string) (agentConfig rsc.AgentConfigura NetworkRouter: networkRouterPtr, RouterConfig: routerConfig, TimeZone: agentInfo.TimeZone, + NatsMode: agentInfo.NatsMode, + NatsServerPort: agentInfo.NatsServerPort, + NatsLeafPort: agentInfo.NatsLeafPort, + NatsClusterPort: agentInfo.NatsClusterPort, + NatsMqttPort: agentInfo.NatsMqttPort, + NatsHttpPort: agentInfo.NatsHttpPort, + JsStorageSize: agentInfo.JsStorageSize, + JsMemoryStoreSize: agentInfo.JsMemoryStoreSize, + UpstreamNatsServers: agentInfo.UpstreamNatsServers, }, } diff --git a/pkg/iofog/constants.go b/pkg/iofog/constants.go index 8c8e89b..a6f7b54 100644 --- a/pkg/iofog/constants.go +++ b/pkg/iofog/constants.go @@ -32,4 +32,5 @@ const ( // RouterMode values RouterModeInterior string = "interior" + NatsModeServer string = "server" ) diff --git a/pkg/iofog/install/controller.go b/pkg/iofog/install/controller.go index 9bc22c1..5e22cc4 100644 --- a/pkg/iofog/install/controller.go +++ b/pkg/iofog/install/controller.go @@ -630,13 +630,14 @@ func (ctrl *Controller) waitForControllerToStart() (string, error) { func (ctrl *Controller) deployRouterCertificates(endpoint string) error { if ctrl.SiteCA != nil { - if err := DeployRouterSecrets(endpoint, "pot-site-ca", ctrl.SiteCA.TLSCert, ctrl.SiteCA.TLSKey); err != nil { + if err := DeployRouterSecrets(endpoint, "router-site-ca", ctrl.SiteCA.TLSCert, ctrl.SiteCA.TLSKey); err != nil { return err } - if err := ImportRouterCertificate(endpoint, "pot-site-ca"); err != nil { + if err := ImportRouterCertificate(endpoint, "router-site-ca"); err != nil { return err } } + // TODO: Remove LocalCA as it is only valid for k8s deployments. Also remove LocalCA from Remote ControllerOptions. if ctrl.LocalCA != nil { if err := DeployRouterSecrets(endpoint, "default-router-local-ca", ctrl.LocalCA.TLSCert, ctrl.LocalCA.TLSKey); err != nil { return err From 2dd1166298a12a7e2edfce10c08943f0cce121f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emirhan=20Durmu=C5=9F?= Date: Wed, 4 Mar 2026 22:59:42 +0300 Subject: [PATCH 2/2] Component tags (operator, controller, agent, router) and iofog-go-sdk/iofog-operator are updated to 3.7.0; build config adds a NATS image tag. ServiceAccounts are now application-scoped: delete/describe require APPLICATION_NAME/SERVICE_ACCOUNT_NAME, the API and types include applicationName, and get/list plus docs are updated accordingly. Control plane deploy (K8s, local, remote) gains NATS (image, services, ingress, replicas, JetStream) and Vault (spec and provider configs for hashicorp, aws, azure, google), wired through install and airgap. --- .goreleaser-potctl-dev.yml | 39 +-- .goreleaser-potctl.yml | 65 ++-- Makefile | 17 +- docs/md/potctl_delete_serviceaccount.md | 6 +- docs/md/potctl_describe_serviceaccount.md | 6 +- go.mod | 4 +- go.sum | 8 +- internal/cmd/delete_serviceaccount.go | 6 +- internal/cmd/describe_serviceaccount.go | 6 +- internal/config/types.go | 7 +- internal/delete/controller/local.go | 2 +- .../delete/serviceaccount/serviceaccount.go | 23 +- internal/deploy/agent/local.go | 2 +- internal/deploy/agent/remote.go | 5 +- internal/deploy/agentconfig/utils.go | 20 +- internal/deploy/airgap/images.go | 284 +++++++++++------- internal/deploy/controller/local/local.go | 15 +- internal/deploy/controller/remote/remote.go | 79 ++++- internal/deploy/controlplane/k8s/execute.go | 99 +++++- .../deploy/controlplane/remote/execute.go | 118 +++++++- internal/deploy/execute.go | 36 ++- internal/deploy/microservice/factory.go | 12 +- internal/deploy/natsaccountrule/factory.go | 30 +- internal/deploy/natsuserrule/factory.go | 30 +- internal/deploy/serviceaccount/factory.go | 14 +- internal/describe/serviceaccount.go | 34 ++- internal/execute/utils.go | 7 +- internal/get/serviceaccount.go | 5 +- internal/resource/k8s_controlplane.go | 20 +- internal/resource/local_controlplane.go | 30 +- internal/resource/remote_controlplane.go | 5 + internal/resource/types.go | 91 +++++- internal/util/client/api.go | 35 ++- internal/util/client/client.go | 17 +- pkg/iofog/constants.go | 1 + pkg/iofog/install/controller.go | 98 +++++- pkg/iofog/install/k8s.go | 54 +++- pkg/iofog/install/k8s_microservices.go | 1 + pkg/iofog/install/local_container.go | 29 +- pkg/iofog/install/types.go | 42 +++ pkg/util/version.go | 3 + 41 files changed, 1092 insertions(+), 313 deletions(-) diff --git a/.goreleaser-potctl-dev.yml b/.goreleaser-potctl-dev.yml index 540d0e1..7ef5a2e 100644 --- a/.goreleaser-potctl-dev.yml +++ b/.goreleaser-potctl-dev.yml @@ -34,13 +34,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" - id: build_linux @@ -61,13 +62,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" flags: - -v @@ -85,13 +87,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" diff --git a/.goreleaser-potctl.yml b/.goreleaser-potctl.yml index 977dde1..2b17340 100644 --- a/.goreleaser-potctl.yml +++ b/.goreleaser-potctl.yml @@ -37,13 +37,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" - id: build_linux_amd64 @@ -62,12 +63,13 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" - id: build_linux_arm64 @@ -89,12 +91,13 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" - id: build_linux_arm @@ -119,13 +122,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" - id: build_windows @@ -144,13 +148,14 @@ builds: - -s -w -X "github.com/datasance/potctl/pkg/util.commit={{ .ShortCommit }}" - -s -w -X "github.com/datasance/potctl/pkg/util.date={{.Date}}" - -s -w -X "github.com/datasance/potctl/pkg/util.platform={{.Os}}/{{.Arch}}" - - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.6.0" - - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.6.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.operatorTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.routerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentTag=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.controllerVersion=3.7.0" + - -s -w -X "github.com/datasance/potctl/pkg/util.agentVersion=3.7.0" - -s -w -X "github.com/datasance/potctl/pkg/util.debuggerTag=latest" + - -s -w -X "github.com/datasance/potctl/pkg/util.natsTag=3.6.0" - -s -w -X "github.com/datasance/potctl/pkg/util.repo=ghcr.io/datasance" diff --git a/Makefile b/Makefile index 17accbc..8a7ffe9 100644 --- a/Makefile +++ b/Makefile @@ -19,16 +19,17 @@ COMMIT ?= $(shell git rev-parse HEAD 2>/dev/null) BUILD_DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) PREFIX = github.com/datasance/potctl/pkg/util LDFLAGS += -X $(PREFIX).versionNumber=$(VERSION) -X $(PREFIX).commit=$(COMMIT) -X $(PREFIX).date=$(BUILD_DATE) -X $(PREFIX).platform=$(GOOS)/$(GOARCH) -LDFLAGS += -X $(PREFIX).operatorTag=3.6.0 -LDFLAGS += -X $(PREFIX).routerTag=3.6.0 -LDFLAGS += -X $(PREFIX).controllerTag=3.6.0 -LDFLAGS += -X $(PREFIX).agentTag=3.6.0 -LDFLAGS += -X $(PREFIX).controllerVersion=3.6.0 -LDFLAGS += -X $(PREFIX).agentVersion=3.6.0 +LDFLAGS += -X $(PREFIX).operatorTag=3.7.0 +LDFLAGS += -X $(PREFIX).routerTag=3.7.0 +LDFLAGS += -X $(PREFIX).controllerTag=3.7.0 +LDFLAGS += -X $(PREFIX).agentTag=3.7.0 +LDFLAGS += -X $(PREFIX).controllerVersion=3.7.0 +LDFLAGS += -X $(PREFIX).agentVersion=3.7.0 LDFLAGS += -X $(PREFIX).debuggerTag=latest +LDFLAGS += -X $(PREFIX).natsTag=2.12.4 LDFLAGS += -X $(PREFIX).repo=ghcr.io/datasance -GO_SDK_MODULE = iofog-go-sdk/v3@v3.6.0 -OPERATOR_MODULE = iofog-operator/v3@v3.6.0 +GO_SDK_MODULE = iofog-go-sdk/v3@v3.7.0 +OPERATOR_MODULE = iofog-operator/v3@v3.7.0 REPORTS_DIR ?= reports TEST_RESULTS ?= TEST-potctl.txt TEST_REPORT ?= TEST-potctl.xml diff --git a/docs/md/potctl_delete_serviceaccount.md b/docs/md/potctl_delete_serviceaccount.md index 3280e9d..f58ff28 100644 --- a/docs/md/potctl_delete_serviceaccount.md +++ b/docs/md/potctl_delete_serviceaccount.md @@ -4,16 +4,16 @@ Delete a ServiceAccount ### Synopsis -Delete a ServiceAccount from the Controller. +Delete a ServiceAccount from the Controller. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa). ``` -potctl delete serviceaccount NAME [flags] +potctl delete serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME [flags] ``` ### Examples ``` -potctl delete serviceaccount NAME +potctl delete serviceaccount myapp/my-sa ``` ### Options diff --git a/docs/md/potctl_describe_serviceaccount.md b/docs/md/potctl_describe_serviceaccount.md index c1f5b5d..38d513c 100644 --- a/docs/md/potctl_describe_serviceaccount.md +++ b/docs/md/potctl_describe_serviceaccount.md @@ -4,16 +4,16 @@ Get detailed information about a ServiceAccount ### Synopsis -Get detailed information about a ServiceAccount. +Get detailed information about a ServiceAccount. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa). ``` -potctl describe serviceaccount NAME [flags] +potctl describe serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME [flags] ``` ### Examples ``` -potctl describe serviceaccount NAME +potctl describe serviceaccount myapp/my-sa ``` ### Options diff --git a/go.mod b/go.mod index a237bc5..5033144 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/GeertJohan/go.rice v1.0.2 github.com/briandowns/spinner v1.23.1 github.com/containers/image/v5 v5.32.1 - github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0 - github.com/datasance/iofog-operator/v3 v3.7.0-beta.0 + github.com/datasance/iofog-go-sdk/v3 v3.7.0 + github.com/datasance/iofog-operator/v3 v3.7.0 github.com/docker/docker v27.4.1+incompatible github.com/docker/go-connections v0.5.0 github.com/gorilla/websocket v1.5.3 diff --git a/go.sum b/go.sum index e53f6a1..95df042 100644 --- a/go.sum +++ b/go.sum @@ -58,10 +58,10 @@ github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzw github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M= github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= -github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0 h1:rRbLMsvVoZvuzthV0c4Rt+9Xu/whYqGWFETQSZeztss= -github.com/datasance/iofog-go-sdk/v3 v3.7.0-beta.0/go.mod h1:mLHD3oHazNzKsV8HoWDsI4g613fHs+rKPUFtYf0tB/U= -github.com/datasance/iofog-operator/v3 v3.7.0-beta.0 h1:Hj5q7F4ysCY75n5GGLuye0fOmc/rEFVXeHkx//8ZQz8= -github.com/datasance/iofog-operator/v3 v3.7.0-beta.0/go.mod h1:FvptSLzx4itiRYmGecx8zA+LpEnqRWuz1a1GzB7Rypc= +github.com/datasance/iofog-go-sdk/v3 v3.7.0 h1:j9ceWQdOXVvF2xAjAtZ+19/28c2WUuM5g4kKG+LVYQQ= +github.com/datasance/iofog-go-sdk/v3 v3.7.0/go.mod h1:mLHD3oHazNzKsV8HoWDsI4g613fHs+rKPUFtYf0tB/U= +github.com/datasance/iofog-operator/v3 v3.7.0 h1:mpElYn6F4dJpZVKh4BVKvlZ4tOdQhiowjGdSQzKOxd8= +github.com/datasance/iofog-operator/v3 v3.7.0/go.mod h1:X0UeJqm9Hocc3//krrpEoBD+G2/tiqEK/qeWMMk/z54= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= diff --git a/internal/cmd/delete_serviceaccount.go b/internal/cmd/delete_serviceaccount.go index c32b40f..c1c4494 100644 --- a/internal/cmd/delete_serviceaccount.go +++ b/internal/cmd/delete_serviceaccount.go @@ -21,10 +21,10 @@ import ( func newDeleteServiceAccountCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "serviceaccount NAME", + Use: "serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME", Short: "Delete a ServiceAccount", - Long: `Delete a ServiceAccount from the Controller.`, - Example: `potctl delete serviceaccount NAME`, + Long: `Delete a ServiceAccount from the Controller. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa).`, + Example: `potctl delete serviceaccount myapp/my-sa`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { name := args[0] diff --git a/internal/cmd/describe_serviceaccount.go b/internal/cmd/describe_serviceaccount.go index 421cb5e..7b0d2ef 100644 --- a/internal/cmd/describe_serviceaccount.go +++ b/internal/cmd/describe_serviceaccount.go @@ -25,10 +25,10 @@ func newDescribeServiceAccountCommand() *cobra.Command { } cmd := &cobra.Command{ - Use: "serviceaccount NAME", + Use: "serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME", Short: "Get detailed information about a ServiceAccount", - Long: `Get detailed information about a ServiceAccount.`, - Example: `potctl describe serviceaccount NAME`, + Long: `Get detailed information about a ServiceAccount. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa).`, + Example: `potctl describe serviceaccount myapp/my-sa`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { var err error diff --git a/internal/config/types.go b/internal/config/types.go index a9bfffd..0cd9d10 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -64,7 +64,8 @@ type potctlNamespace struct { // HeaderMetadata contains k8s metadata type HeaderMetadata struct { - Name string `yaml:"name" json:"name"` - Namespace string `yaml:"namespace" json:"namespace"` - Tags *[]string `yaml:"tags,omitempty" json:"tags,omitempty"` + Name string `yaml:"name" json:"name"` + Namespace string `yaml:"namespace" json:"namespace"` + ApplicationName string `yaml:"applicationName,omitempty" json:"applicationName,omitempty"` // used by ServiceAccount (application-scoped) + Tags *[]string `yaml:"tags,omitempty" json:"tags,omitempty"` } diff --git a/internal/delete/controller/local.go b/internal/delete/controller/local.go index 9e6e7fa..5017ec8 100644 --- a/internal/delete/controller/local.go +++ b/internal/delete/controller/local.go @@ -34,7 +34,7 @@ func NewLocalExecutor(controlPlane *rsc.LocalControlPlane, namespace, name strin controlPlane: controlPlane, namespace: namespace, name: name, - localControllerConfig: install.NewLocalControllerConfig("", install.Credentials{}, install.Auth{}, install.Database{}, install.Events{}), + localControllerConfig: install.NewLocalControllerConfig("", install.Credentials{}, install.Auth{}, install.Database{}, install.Events{}, nil), } return exe } diff --git a/internal/delete/serviceaccount/serviceaccount.go b/internal/delete/serviceaccount/serviceaccount.go index 1141866..e264255 100644 --- a/internal/delete/serviceaccount/serviceaccount.go +++ b/internal/delete/serviceaccount/serviceaccount.go @@ -14,6 +14,8 @@ package deleteserviceaccount import ( + "strings" + "github.com/datasance/potctl/internal/execute" clientutil "github.com/datasance/potctl/internal/util/client" "github.com/datasance/potctl/pkg/util" @@ -21,25 +23,42 @@ import ( type Executor struct { namespace string + appName string name string } +// parseServiceAccountName returns (appName, name). Name must be "appName/name" (application-scoped). +func parseServiceAccountName(arg string) (appName, name string) { + if idx := strings.Index(arg, "/"); idx >= 0 { + return arg[:idx], arg[idx+1:] + } + return "", arg +} + func NewExecutor(namespace, name string) (execute.Executor, error) { + appName, saName := parseServiceAccountName(name) return &Executor{ namespace: namespace, - name: name, + appName: appName, + name: saName, }, nil } func (exe *Executor) GetName() string { + if exe.appName != "" { + return exe.appName + "/" + exe.name + } return exe.name } func (exe *Executor) Execute() error { + if exe.appName == "" { + return util.NewInputError("ServiceAccount is application-scoped: use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa)") + } util.SpinStart("Deleting ServiceAccount") clt, err := clientutil.NewControllerClient(exe.namespace) if err != nil { return err } - return clt.DeleteServiceAccount(exe.name) + return clt.DeleteServiceAccount(exe.appName, exe.name) } diff --git a/internal/deploy/agent/local.go b/internal/deploy/agent/local.go index 00f66e2..4b312ed 100644 --- a/internal/deploy/agent/local.go +++ b/internal/deploy/agent/local.go @@ -40,7 +40,7 @@ func newLocalExecutor(namespace string, agent *rsc.LocalAgent, isSystem bool) (* agent.Config = &rsc.AgentConfiguration{} } // Get Controller LocalContainerConfig - controllerContainerConfig := install.NewLocalControllerConfig("", install.Credentials{}, install.Auth{}, install.Database{}, install.Events{}) + controllerContainerConfig := install.NewLocalControllerConfig("", install.Credentials{}, install.Auth{}, install.Database{}, install.Events{}, nil) return &localExecutor{ isSystem: isSystem, namespace: namespace, diff --git a/internal/deploy/agent/remote.go b/internal/deploy/agent/remote.go index 465855b..949d7fb 100644 --- a/internal/deploy/agent/remote.go +++ b/internal/deploy/agent/remote.go @@ -265,11 +265,14 @@ func (exe *remoteExecutor) Execute() (err error) { return fmt.Errorf("failed to get router image for platform %s: %w", platform, err) } - // Prepare image list (agent, router for platform, debugger if available) + // Prepare image list (agent, router for platform, NATS, debugger if available) imageList := []string{images.Agent} if routerImage != "" { imageList = append(imageList, routerImage) } + if images.Nats != "" { + imageList = append(imageList, images.Nats) + } if images.Debugger != "" { imageList = append(imageList, images.Debugger) } diff --git a/internal/deploy/agentconfig/utils.go b/internal/deploy/agentconfig/utils.go index 43f5bfe..20b6cb8 100644 --- a/internal/deploy/agentconfig/utils.go +++ b/internal/deploy/agentconfig/utils.go @@ -24,13 +24,15 @@ import ( type RouterMode string +type NatsMode string + const ( EdgeRouter RouterMode = "edge" InteriorRouter RouterMode = "interior" NoneRouter RouterMode = "none" - NatsNone string = "none" - NatsLeaf string = "leaf" - NatsServer string = "server" + NatsNone NatsMode = "none" + NatsLeaf NatsMode = "leaf" + NatsServer NatsMode = "server" ) func getRouterMode(config *rsc.AgentConfiguration) RouterMode { @@ -40,8 +42,16 @@ func getRouterMode(config *rsc.AgentConfiguration) RouterMode { return EdgeRouter } +func getNatsMode(config *rsc.AgentConfiguration) NatsMode { + if config.NatsConfig.NatsMode != nil { + return NatsMode(*config.NatsConfig.NatsMode) + } + return NatsLeaf +} + func Validate(config *rsc.AgentConfiguration) error { routerMode := getRouterMode(config) + natsMode := getNatsMode(config) if routerMode != EdgeRouter && routerMode != InteriorRouter && routerMode != NoneRouter { msg := "agent config %s validation failed. RouterMode has to be one of edge, interior, none. Default is: edge" @@ -59,8 +69,8 @@ func Validate(config *rsc.AgentConfiguration) error { msg := "agent config %s validation failed. Cannot have an edgeRouterPort or interRouterPort if routerMode is different from interior. Current router mode is: %s" return util.NewInputError(fmt.Sprintf(msg, config.Name, routerMode)) } - if config.NatsMode != nil && *config.NatsMode != NatsNone && *config.NatsMode != NatsLeaf && *config.NatsMode != NatsServer { - msg := "agent config %s validation failed. natsMode has to be one of none, leaf, server" + if natsMode != NatsServer && (config.NatsConfig.NatsClusterPort != nil) { + msg := "agent config %s validation failed. Cannot have a natsClusterPort if natsMode is different from server" return util.NewInputError(fmt.Sprintf(msg, config.Name)) } diff --git a/internal/deploy/airgap/images.go b/internal/deploy/airgap/images.go index 687580a..c7ce67c 100644 --- a/internal/deploy/airgap/images.go +++ b/internal/deploy/airgap/images.go @@ -16,91 +16,181 @@ type RequiredImages struct { Agent string RouterX86 string RouterARM string + Nats string Debugger string } -// CollectControllerImages collects required images for controller deployment -// For initial deployment: uses YAML/defaults -// For existing control plane: fetches router/debugger from controller catalog items -func CollectControllerImages(namespace string, controlPlane *rsc.RemoteControlPlane, isInitialDeployment bool) (*RequiredImages, error) { - images := &RequiredImages{} +// getCatalogItemByName tries the given name, then fallbackNames if the first lookup fails (e.g. casing). +func getCatalogItemByName(clt *client.Client, name string, fallbackNames ...string) (item *client.CatalogItemInfo, err error) { + item, err = clt.GetCatalogItemByName(name) + if err == nil { + return item, nil + } + for _, n := range fallbackNames { + item, err = clt.GetCatalogItemByName(n) + if err == nil { + return item, nil + } + } + return nil, err +} - // Controller image - if controlPlane.Package.Container.Image != "" { - images.Controller = controlPlane.Package.Container.Image - } else { - images.Controller = util.GetControllerImage() +// applyRouterImagesFromCatalog sets RouterX86 and RouterARM from catalog item images. +func applyRouterImagesFromCatalog(images *RequiredImages, item *client.CatalogItemInfo) { + if item == nil || len(item.Images) == 0 { + return + } + for _, img := range item.Images { + switch client.AgentTypeIDAgentTypeDict[img.AgentTypeID] { + case "x86": + images.RouterX86 = img.ContainerImage + case "arm": + images.RouterARM = img.ContainerImage + } } +} - // Router and debugger images - if isInitialDeployment { - // Use YAML or defaults - if controlPlane.SystemMicroservices.Router.X86 != "" { - images.RouterX86 = controlPlane.SystemMicroservices.Router.X86 +// applyDebuggerImageFromCatalog sets Debugger from catalog item (first x86 or arm image). +func applyDebuggerImageFromCatalog(images *RequiredImages, item *client.CatalogItemInfo) { + if item == nil || len(item.Images) == 0 { + return + } + for _, img := range item.Images { + if client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "x86" || client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "arm" { + images.Debugger = img.ContainerImage + return + } + } +} + +// applyNatsImageFromCatalog sets Nats from catalog item (first image). +func applyNatsImageFromCatalog(images *RequiredImages, item *client.CatalogItemInfo) { + if item == nil || len(item.Images) == 0 { + return + } + images.Nats = item.Images[0].ContainerImage +} + +// applyYAMLFallbackForController fills any empty router/nats/debugger from controlPlane.SystemMicroservices; util is last fallback. +func applyYAMLAndUtilFallbackForController(images *RequiredImages, controlPlane *rsc.RemoteControlPlane) { + if controlPlane == nil { + return + } + sm := &controlPlane.SystemMicroservices + if images.RouterX86 == "" { + if sm.Router.X86 != "" { + images.RouterX86 = sm.Router.X86 } else { images.RouterX86 = util.GetRouterImage() } + } + if images.RouterARM == "" { + if sm.Router.ARM != "" { + images.RouterARM = sm.Router.ARM + } else { + images.RouterARM = util.GetRouterARMImage() + } + } + if images.Nats == "" { + if sm.Nats.X86 != "" { + images.Nats = sm.Nats.X86 + } else if sm.Nats.ARM != "" { + images.Nats = sm.Nats.ARM + } else { + images.Nats = util.GetNatsImage() + } + } + if images.Debugger == "" { + images.Debugger = util.GetDebuggerImage() + } +} - if controlPlane.SystemMicroservices.Router.ARM != "" { +// applyYAMLAndUtilFallbackForAgent fills any empty router/nats/debugger from controlPlane (if non-nil) then util. +func applyYAMLAndUtilFallbackForAgent(images *RequiredImages, controlPlane *rsc.RemoteControlPlane) { + if images.RouterX86 == "" { + if controlPlane != nil && controlPlane.SystemMicroservices.Router.X86 != "" { + images.RouterX86 = controlPlane.SystemMicroservices.Router.X86 + } else { + images.RouterX86 = util.GetRouterImage() + } + } + if images.RouterARM == "" { + if controlPlane != nil && controlPlane.SystemMicroservices.Router.ARM != "" { images.RouterARM = controlPlane.SystemMicroservices.Router.ARM } else { images.RouterARM = util.GetRouterARMImage() } - - // Debugger image - // TODO: Add debugger image to RemoteSystemMicroservices + } + if images.Nats == "" { + if controlPlane != nil { + if controlPlane.SystemMicroservices.Nats.X86 != "" { + images.Nats = controlPlane.SystemMicroservices.Nats.X86 + } else if controlPlane.SystemMicroservices.Nats.ARM != "" { + images.Nats = controlPlane.SystemMicroservices.Nats.ARM + } + if images.Nats == "" { + images.Nats = util.GetNatsImage() + } + } else { + images.Nats = util.GetNatsImage() + } + } + if images.Debugger == "" { + // RemoteSystemMicroservices has no Debugger field; use util as fallback images.Debugger = util.GetDebuggerImage() + } +} + +// CollectControllerImages collects required images for controller deployment. +// When a controller already exists (!isInitialDeployment): catalog first, then YAML, then util. +// When no controller yet (isInitialDeployment): YAML then util (no catalog). +func CollectControllerImages(namespace string, controlPlane *rsc.RemoteControlPlane, isInitialDeployment bool) (*RequiredImages, error) { + images := &RequiredImages{} + + // Controller image + if controlPlane.Package.Container.Image != "" { + images.Controller = controlPlane.Package.Container.Image } else { - // Fetch from controller catalog items - clt, err := clientutil.NewControllerClient(namespace) - if err != nil { - return nil, fmt.Errorf("failed to connect to controller: %w", err) - } + images.Controller = util.GetControllerImage() + } - // Get router catalog item - routerItem, err := clt.GetCatalogItemByName("router") - if err != nil { - return nil, fmt.Errorf("failed to get router catalog item from controller: %w", err) - } + if isInitialDeployment { + // No controller to query; use YAML then util + applyYAMLAndUtilFallbackForController(images, controlPlane) + return images, nil + } - // Extract router images from catalog item - for _, img := range routerItem.Images { - switch client.AgentTypeIDAgentTypeDict[img.AgentTypeID] { - case "x86": - images.RouterX86 = img.ContainerImage - case "arm": - images.RouterARM = img.ContainerImage - } - } + // Controller exists: try catalog first, then YAML, then util + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, fmt.Errorf("failed to connect to controller: %w", err) + } - // Get debugger catalog item - debuggerItem, err := clt.GetCatalogItemByName("debugger") - if err != nil { - // Debugger is optional, log but don't fail - util.PrintNotify("Warning: Could not fetch debugger catalog item from controller. Debugger image will not be transferred.") - images.Debugger = "" - } else { - // Extract debugger image (typically x86, but check both) - for _, img := range debuggerItem.Images { - if client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "x86" { - images.Debugger = img.ContainerImage - break - } else if client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "arm" { - images.Debugger = img.ContainerImage - break - } - } - } + routerItem, err := getCatalogItemByName(clt, "router", "Router") + if err == nil { + applyRouterImagesFromCatalog(images, routerItem) + } + + debuggerItem, err := getCatalogItemByName(clt, "debugger", "Debug") + if err == nil { + applyDebuggerImageFromCatalog(images, debuggerItem) + } else { + util.PrintNotify("Warning: Could not fetch debugger catalog item from controller. Debugger image will not be transferred.") + } + + natsItem, err := getCatalogItemByName(clt, "nats", "NATS") + if err == nil { + applyNatsImageFromCatalog(images, natsItem) } + applyYAMLAndUtilFallbackForController(images, controlPlane) return images, nil } -// CollectAgentImages collects required images for agent deployment -// For initial deployment: uses YAML/defaults (only for RemoteControlPlane) -// For existing control plane: fetches router/debugger from controller catalog items -// controlPlane can be nil for Kubernetes or other non-remote control planes -func CollectAgentImages(namespace string, agent *rsc.RemoteAgent, controlPlane *rsc.RemoteControlPlane, isInitialDeployment bool) (*RequiredImages, error) { +// CollectAgentImages collects required images for agent deployment. +// When deploying an agent, a controller already exists; so we always try catalog first, then YAML, then util. +// controlPlane can be nil for Kubernetes or other non-remote control planes (catalog + util still apply). +func CollectAgentImages(namespace string, agent *rsc.RemoteAgent, controlPlane *rsc.RemoteControlPlane, _ bool) (*RequiredImages, error) { images := &RequiredImages{} // Agent image @@ -110,66 +200,30 @@ func CollectAgentImages(namespace string, agent *rsc.RemoteAgent, controlPlane * images.Agent = util.GetAgentImage() } - // Router and debugger images - if isInitialDeployment && controlPlane != nil { - // Use YAML or defaults (only for RemoteControlPlane initial deployment) - if controlPlane.SystemMicroservices.Router.X86 != "" { - images.RouterX86 = controlPlane.SystemMicroservices.Router.X86 - } else { - images.RouterX86 = util.GetRouterImage() - } + // Router, NATS, debugger: catalog first (controller must exist when deploying agent), then YAML, then util + clt, err := clientutil.NewControllerClient(namespace) + if err != nil { + return nil, fmt.Errorf("failed to connect to controller: %w", err) + } - if controlPlane.SystemMicroservices.Router.ARM != "" { - images.RouterARM = controlPlane.SystemMicroservices.Router.ARM - } else { - images.RouterARM = util.GetRouterARMImage() - } + routerItem, err := getCatalogItemByName(clt, "router", "Router") + if err == nil { + applyRouterImagesFromCatalog(images, routerItem) + } - // Debugger image - no default in YAML structure - images.Debugger = "" + debuggerItem, err := getCatalogItemByName(clt, "debugger", "Debug") + if err == nil { + applyDebuggerImageFromCatalog(images, debuggerItem) } else { - // Fetch from controller catalog items (for existing control plane or non-remote control planes) - clt, err := clientutil.NewControllerClient(namespace) - if err != nil { - return nil, fmt.Errorf("failed to connect to controller: %w", err) - } - - // Get router catalog item - routerItem, err := clt.GetCatalogItemByName("Router") - if err != nil { - return nil, fmt.Errorf("failed to get router catalog item from controller: %w", err) - } - - // Extract router images from catalog item - for _, img := range routerItem.Images { - switch client.AgentTypeIDAgentTypeDict[img.AgentTypeID] { - case "x86": - images.RouterX86 = img.ContainerImage - case "arm": - images.RouterARM = img.ContainerImage - } - } + util.PrintNotify("Warning: Could not fetch debugger catalog item from controller. Debugger image will not be transferred.") + } - // Get debugger catalog item - debuggerItem, err := clt.GetCatalogItemByName("Debug") - if err != nil { - // Debugger is optional, log but don't fail - util.PrintNotify("Warning: Could not fetch debugger catalog item from controller. Debugger image will not be transferred.") - images.Debugger = "" - } else { - // Extract debugger image (typically x86, but check both) - for _, img := range debuggerItem.Images { - if client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "x86" { - images.Debugger = img.ContainerImage - break - } else if client.AgentTypeIDAgentTypeDict[img.AgentTypeID] == "arm" { - images.Debugger = img.ContainerImage - break - } - } - } + natsItem, err := getCatalogItemByName(clt, "nats") + if err == nil { + applyNatsImageFromCatalog(images, natsItem) } + applyYAMLAndUtilFallbackForAgent(images, controlPlane) return images, nil } diff --git a/internal/deploy/controller/local/local.go b/internal/deploy/controller/local/local.go index 6fbaa80..b296a8f 100644 --- a/internal/deploy/controller/local/local.go +++ b/internal/deploy/controller/local/local.go @@ -127,7 +127,7 @@ func newExecutor(namespace string, controlPlane *rsc.LocalControlPlane, ctrl *rs RetentionDays: controlPlane.Events.RetentionDays, CleanupInterval: controlPlane.Events.CleanupInterval, CaptureIpAddress: controlPlane.Events.CaptureIpAddress, - }), + }, localSystemImagesToInstall(controlPlane.SystemMicroservices, controlPlane.Nats)), iofogUser: controlPlane.GetUser(), ctrlPlane: controlPlane, } @@ -200,6 +200,19 @@ func (exe *localExecutor) Execute() error { return exe.ctrlPlane.UpdateController(exe.ctrl) } +func localSystemImagesToInstall(s *rsc.LocalSystemMicroservices, nats *rsc.NatsEnabledConfig) *install.LocalSystemImages { + // Always pass a non-nil struct so local controller gets default NATS_IMAGE_1/2 and NATS_ENABLED when not overridden + out := &install.LocalSystemImages{} + if s != nil { + out.Router = s.Router + out.Nats = s.Nats + } + if nats != nil && nats.Enabled != nil { + out.NatsEnabled = nats.Enabled + } + return out +} + func Validate(ctrl rsc.Controller) error { if err := util.IsLowerAlphanumeric("Controller", ctrl.GetName()); err != nil { return err diff --git a/internal/deploy/controller/remote/remote.go b/internal/deploy/controller/remote/remote.go index 1cf1f9d..123880b 100644 --- a/internal/deploy/controller/remote/remote.go +++ b/internal/deploy/controller/remote/remote.go @@ -109,20 +109,20 @@ func (exe *remoteExecutor) Execute() (err error) { } // Instantiate deployer controllerOptions := &install.ControllerOptions{ - Namespace: exe.namespace, - User: exe.controller.SSH.User, - Host: exe.controller.Host, - Port: exe.controller.SSH.Port, - PrivKeyFilename: exe.controller.SSH.KeyFile, - PidBaseDir: exe.controller.PidBaseDir, - EcnViewerPort: exe.controller.EcnViewerPort, - EcnViewerURL: exe.controller.EcnViewerURL, - LogLevel: exe.controller.LogLevel, - Version: exe.controlPlane.Package.Version, - Image: exe.controlPlane.Package.Container.Image, - // Repo: exe.controlPlane.Package.Repo, - // Token: exe.controlPlane.Package.Token, + Namespace: exe.namespace, + User: exe.controller.SSH.User, + Host: exe.controller.Host, + Port: exe.controller.SSH.Port, + PrivKeyFilename: exe.controller.SSH.KeyFile, + PidBaseDir: exe.controller.PidBaseDir, + EcnViewerPort: exe.controller.EcnViewerPort, + EcnViewerURL: exe.controller.EcnViewerURL, + LogLevel: exe.controller.LogLevel, + Version: exe.controlPlane.Package.Version, + Image: exe.controlPlane.Package.Container.Image, SystemMicroservices: exe.controlPlane.SystemMicroservices, + NatsEnabled: natsEnabledFromSpec(exe.controlPlane.Nats), + Vault: vaultSpecToInstall(exe.controlPlane.Vault), } // Add HTTPS configuration if present @@ -217,6 +217,59 @@ func (exe *remoteExecutor) setDefaultValues() { if exe.controlPlane.SystemMicroservices.Router.ARM == "" { exe.controlPlane.SystemMicroservices.Router.ARM = util.GetRouterARMImage() } + if exe.controlPlane.SystemMicroservices.Nats.X86 == "" { + exe.controlPlane.SystemMicroservices.Nats.X86 = util.GetNatsImage() + } + if exe.controlPlane.SystemMicroservices.Nats.ARM == "" { + exe.controlPlane.SystemMicroservices.Nats.ARM = util.GetNatsImage() + } +} + +func natsEnabledFromSpec(n *rsc.NatsEnabledConfig) *bool { + if n == nil || n.Enabled == nil { + return nil + } + return n.Enabled +} + +func vaultSpecToInstall(v *rsc.VaultSpec) *install.VaultConfig { + if v == nil { + return nil + } + out := &install.VaultConfig{ + Enabled: v.Enabled, + Provider: v.Provider, + BasePath: v.BasePath, + } + if v.Hashicorp != nil { + out.Hashicorp = &install.VaultHashicorpConfig{ + Address: v.Hashicorp.Address, + Token: v.Hashicorp.Token, + Mount: v.Hashicorp.Mount, + } + } + if v.Aws != nil { + out.Aws = &install.VaultAwsConfig{ + Region: v.Aws.Region, + AccessKeyId: v.Aws.AccessKeyId, + AccessKey: v.Aws.AccessKey, + } + } + if v.Azure != nil { + out.Azure = &install.VaultAzureConfig{ + URL: v.Azure.URL, + TenantId: v.Azure.TenantId, + ClientId: v.Azure.ClientId, + ClientSecret: v.Azure.ClientSecret, + } + } + if v.Google != nil { + out.Google = &install.VaultGoogleConfig{ + ProjectId: v.Google.ProjectId, + Credentials: v.Google.Credentials, + } + } + return out } func Validate(ctrl rsc.Controller) error { diff --git a/internal/deploy/controlplane/k8s/execute.go b/internal/deploy/controlplane/k8s/execute.go index c32d074..d029a15 100644 --- a/internal/deploy/controlplane/k8s/execute.go +++ b/internal/deploy/controlplane/k8s/execute.go @@ -16,6 +16,7 @@ package deployk8scontrolplane import ( "fmt" + cpv3 "github.com/datasance/iofog-operator/v3/apis/controlplanes/v3" "github.com/datasance/potctl/internal/config" "github.com/datasance/potctl/internal/execute" rsc "github.com/datasance/potctl/internal/resource" @@ -94,10 +95,14 @@ func (exe *kubernetesControlPlaneExecutor) executeInstall() (err error) { installer.SetPullSecret(exe.controlPlane.Images.PullSecret) installer.SetRouterImage(exe.controlPlane.Images.Router) installer.SetControllerImage(exe.controlPlane.Images.Controller) - installer.SetControllerService(exe.controlPlane.Services.Controller.Type, exe.controlPlane.Services.Controller.Address, exe.controlPlane.Services.Controller.Annotations) - installer.SetRouterService(exe.controlPlane.Services.Router.Type, exe.controlPlane.Services.Router.Address, exe.controlPlane.Services.Router.Annotations) + installer.SetNatsImage(exe.controlPlane.Images.Nats) + installer.SetControllerService(exe.controlPlane.Services.Controller.Type, exe.controlPlane.Services.Controller.Address, exe.controlPlane.Services.Controller.Annotations, exe.controlPlane.Services.Controller.ExternalTrafficPolicy) + installer.SetRouterService(exe.controlPlane.Services.Router.Type, exe.controlPlane.Services.Router.Address, exe.controlPlane.Services.Router.Annotations, exe.controlPlane.Services.Router.ExternalTrafficPolicy) + installer.SetNatsService(exe.controlPlane.Services.Nats.Type, exe.controlPlane.Services.Nats.Address, exe.controlPlane.Services.Nats.Annotations, exe.controlPlane.Services.Nats.ExternalTrafficPolicy) + installer.SetNatsServerService(exe.controlPlane.Services.NatsServer.Type, exe.controlPlane.Services.NatsServer.Address, exe.controlPlane.Services.NatsServer.Annotations, exe.controlPlane.Services.NatsServer.ExternalTrafficPolicy) installer.SetControllerIngress(exe.controlPlane.Ingresses.Controller.Annotations, exe.controlPlane.Ingresses.Controller.IngressClassName, exe.controlPlane.Ingresses.Controller.Host, exe.controlPlane.Ingresses.Controller.SecretName) installer.SetRouterIngress(exe.controlPlane.Ingresses.Router.Address, exe.controlPlane.Ingresses.Router.MessagePort, exe.controlPlane.Ingresses.Router.InteriorPort, exe.controlPlane.Ingresses.Router.EdgePort) + installer.SetNatsIngress(exe.controlPlane.Ingresses.Nats.Address, exe.controlPlane.Ingresses.Nats.ServerPort, exe.controlPlane.Ingresses.Nats.ClusterPort, exe.controlPlane.Ingresses.Nats.LeafPort, exe.controlPlane.Ingresses.Nats.MqttPort, exe.controlPlane.Ingresses.Nats.HttpPort) // installer.SetRouterConfig(exe.controlPlane.Router.HA) // Set isViewerDns based on EcnViewerURL presence @@ -110,11 +115,15 @@ func (exe *kubernetesControlPlaneExecutor) executeInstall() (err error) { if exe.controlPlane.Replicas.Controller != 0 { replicas = exe.controlPlane.Replicas.Controller } + replicasNats := exe.controlPlane.Replicas.Nats + natsSpec := natsSpecToCpv3(exe.controlPlane.Nats) + vaultSpec := vaultSpecToCpv3(exe.controlPlane.Vault) // Create controller on cluster // user := install.IofogUser(exe.controlPlane.IofogUser) conf := install.K8SControllerConfig{ // User: user, Replicas: replicas, + ReplicasNats: replicasNats, Auth: install.Auth(exe.controlPlane.Auth), Database: install.Database(exe.controlPlane.Database), Events: install.Events(exe.controlPlane.Events), @@ -124,6 +133,8 @@ func (exe *kubernetesControlPlaneExecutor) executeInstall() (err error) { LogLevel: exe.controlPlane.Controller.LogLevel, Https: exe.controlPlane.Controller.Https, SecretName: exe.controlPlane.Controller.SecretName, + Nats: natsSpec, + Vault: vaultSpec, } endpoint, err := installer.CreateControlPlane(&conf) if err != nil { @@ -190,5 +201,89 @@ func validate(controlPlane *rsc.KubernetesControlPlane) (err error) { return util.NewInputError("When Router service type is ClusterIP, You must provide Ingress configuration for Default-Router") } } + // NATS: when replicas.nats is set it must be >= 2 + if controlPlane.Replicas.Nats > 0 && controlPlane.Replicas.Nats < 2 { + return util.NewInputError("When NATS is enabled, replicas.nats must be at least 2") + } + // Vault: when set, validate provider and required provider fields + if controlPlane.Vault != nil { + if controlPlane.Vault.Provider != "" { + switch controlPlane.Vault.Provider { + case "hashicorp", "openbao", "vault": + if controlPlane.Vault.Hashicorp == nil || (controlPlane.Vault.Hashicorp.Address == "" && controlPlane.Vault.Hashicorp.Token == "") { + return util.NewInputError("Vault provider " + controlPlane.Vault.Provider + " requires hashicorp block with address and token") + } + case "aws", "aws-secrets-manager": + if controlPlane.Vault.Aws == nil { + return util.NewInputError("Vault provider " + controlPlane.Vault.Provider + " requires aws block") + } + case "azure", "azure-key-vault": + if controlPlane.Vault.Azure == nil { + return util.NewInputError("Vault provider " + controlPlane.Vault.Provider + " requires azure block") + } + case "google", "google-secret-manager": + if controlPlane.Vault.Google == nil { + return util.NewInputError("Vault provider " + controlPlane.Vault.Provider + " requires google block") + } + } + } + } return } + +func natsSpecToCpv3(n *rsc.NatsSpec) *cpv3.Nats { + if n == nil { + return nil + } + out := &cpv3.Nats{ + Enabled: n.Enabled, + } + if n.JetStream.StorageSize != "" || n.JetStream.MemoryStoreSize != "" || n.JetStream.StorageClassName != "" { + out.JetStream = cpv3.NatsJetStream{ + StorageSize: n.JetStream.StorageSize, + MemoryStoreSize: n.JetStream.MemoryStoreSize, + StorageClassName: n.JetStream.StorageClassName, + } + } + return out +} + +func vaultSpecToCpv3(v *rsc.VaultSpec) *cpv3.Vault { + if v == nil { + return nil + } + out := &cpv3.Vault{ + Enabled: v.Enabled, + Provider: v.Provider, + BasePath: v.BasePath, + } + if v.Hashicorp != nil { + out.Hashicorp = &cpv3.VaultHashicorp{ + Address: v.Hashicorp.Address, + Token: v.Hashicorp.Token, + Mount: v.Hashicorp.Mount, + } + } + if v.Aws != nil { + out.Aws = &cpv3.VaultAws{ + Region: v.Aws.Region, + AccessKeyId: v.Aws.AccessKeyId, + AccessKey: v.Aws.AccessKey, + } + } + if v.Azure != nil { + out.Azure = &cpv3.VaultAzure{ + URL: v.Azure.URL, + TenantId: v.Azure.TenantId, + ClientId: v.Azure.ClientId, + ClientSecret: v.Azure.ClientSecret, + } + } + if v.Google != nil { + out.Google = &cpv3.VaultGoogle{ + ProjectId: v.Google.ProjectId, + Credentials: v.Google.Credentials, + } + } + return out +} diff --git a/internal/deploy/controlplane/remote/execute.go b/internal/deploy/controlplane/remote/execute.go index 3940f89..3028cfd 100644 --- a/internal/deploy/controlplane/remote/execute.go +++ b/internal/deploy/controlplane/remote/execute.go @@ -40,8 +40,47 @@ import ( const ( deploymentTypeContainer = "container" deploymentTypeNative = "native" + + defaultNatsServerPort = 4222 + defaultNatsClusterPort = 6222 + defaultNatsLeafPort = 7422 + defaultNatsMqttPort = 8883 + defaultNatsHttpPort = 8222 + defaultJsStorageSize = "10G" + defaultJsMemoryStoreSize = "1G" ) +// applySystemAgentNatsDefaults sets NATS config defaults for system agents when not provided (natsMode=server, ports, JsStorageSize, JsMemoryStoreSize). +func applySystemAgentNatsDefaults(cfg *rsc.AgentConfiguration) { + if cfg.NatsConfig.NatsMode == nil { + cfg.NatsConfig.NatsMode = iutil.MakeStrPtr(iofog.NatsModeServer) + } else { + // Force server mode for system agents (like router interior) + cfg.NatsConfig.NatsMode = iutil.MakeStrPtr(iofog.NatsModeServer) + } + if cfg.NatsConfig.NatsServerPort == nil { + cfg.NatsConfig.NatsServerPort = iutil.MakeIntPtr(defaultNatsServerPort) + } + if cfg.NatsConfig.NatsClusterPort == nil { + cfg.NatsConfig.NatsClusterPort = iutil.MakeIntPtr(defaultNatsClusterPort) + } + if cfg.NatsConfig.NatsLeafPort == nil { + cfg.NatsConfig.NatsLeafPort = iutil.MakeIntPtr(defaultNatsLeafPort) + } + if cfg.NatsConfig.NatsMqttPort == nil { + cfg.NatsMqttPort = iutil.MakeIntPtr(defaultNatsMqttPort) + } + if cfg.NatsConfig.NatsHttpPort == nil { + cfg.NatsConfig.NatsHttpPort = iutil.MakeIntPtr(defaultNatsHttpPort) + } + if cfg.NatsConfig.JsStorageSize == nil { + cfg.NatsConfig.JsStorageSize = iutil.MakeStrPtr(defaultJsStorageSize) + } + if cfg.NatsConfig.JsMemoryStoreSize == nil { + cfg.NatsConfig.JsMemoryStoreSize = iutil.MakeStrPtr(defaultJsMemoryStoreSize) + } +} + type Options struct { Namespace string Yaml []byte @@ -97,16 +136,18 @@ func deploySystemAgent(namespace string, ctrl *rsc.RemoteController, systemAgent } upstreamRouters := []string{} + upstreamNatsServers := []string{} deployAgentConfig = rsc.AgentConfiguration{ Name: ctrl.Name, FogType: iutil.MakeStrPtr("auto"), AgentConfiguration: client.AgentConfiguration{ - IsSystem: iutil.MakeBoolPtr(true), - DeploymentType: iutil.MakeStrPtr(deploymentType), - Host: &ctrl.Host, - RouterConfig: RouterConfig, - UpstreamRouters: &upstreamRouters, + IsSystem: iutil.MakeBoolPtr(true), + DeploymentType: iutil.MakeStrPtr(deploymentType), + Host: &ctrl.Host, + RouterConfig: RouterConfig, + UpstreamRouters: &upstreamRouters, + UpstreamNatsServers: &upstreamNatsServers, }, } } @@ -135,6 +176,9 @@ func deploySystemAgent(namespace string, ctrl *rsc.RemoteController, systemAgent deployAgentConfig.RouterConfig.MessagingPort = &messagingPort } + // System agents run NATS in server mode (like router interior). Apply default natsConfig when not provided. + applySystemAgentNatsDefaults(&deployAgentConfig) + // Ensure name is set if deployAgentConfig.Name == "" { deployAgentConfig.Name = ctrl.Name @@ -214,6 +258,23 @@ func deployNextSystemAgent(namespace string, ctrl *rsc.RemoteController, systemA *deployAgentConfig.UpstreamRouters = append(*deployAgentConfig.UpstreamRouters, "default-router") } } + // Override upstream nats server for non-first controllers + if deployAgentConfig.UpstreamNatsServers == nil { + upstreamNatsServers := []string{"default-nats-hub"} + deployAgentConfig.UpstreamNatsServers = &upstreamNatsServers + } else { + // Add default-nats-hub if not already present + hasDefaultNatsHub := false + for _, natsServer := range *deployAgentConfig.UpstreamNatsServers { + if natsServer == "default-nats-hub" { + hasDefaultNatsHub = true + break + } + } + if !hasDefaultNatsHub { + *deployAgentConfig.UpstreamNatsServers = append(*deployAgentConfig.UpstreamNatsServers, "default-nats-hub") + } + } } else { // Use defaults with configurable ports (router mode always interior) RouterConfig := client.RouterConfig{ @@ -261,6 +322,9 @@ func deployNextSystemAgent(namespace string, ctrl *rsc.RemoteController, systemA deployAgentConfig.RouterConfig.MessagingPort = &messagingPort } + // System agents run NATS in server mode (like router interior). Apply default natsConfig when not provided. + applySystemAgentNatsDefaults(&deployAgentConfig) + // Ensure name is set if deployAgentConfig.Name == "" { deployAgentConfig.Name = ctrl.Name @@ -657,6 +721,40 @@ func validateMultiControllerConfig(controlPlane *rsc.RemoteControlPlane) error { return err } + // Validate Vault when set (provider and required provider fields) + if err := validateRemoteVault(controlPlane); err != nil { + return err + } + + return nil +} + +func validateRemoteVault(controlPlane *rsc.RemoteControlPlane) error { + if controlPlane.Vault == nil { + return nil + } + v := controlPlane.Vault + if v.Provider == "" { + return nil + } + switch v.Provider { + case "hashicorp", "openbao", "vault": + if v.Hashicorp == nil || (v.Hashicorp.Address == "" && v.Hashicorp.Token == "") { + return util.NewInputError("Vault provider " + v.Provider + " requires hashicorp block with address and token") + } + case "aws", "aws-secrets-manager": + if v.Aws == nil { + return util.NewInputError("Vault provider " + v.Provider + " requires aws block") + } + case "azure", "azure-key-vault": + if v.Azure == nil { + return util.NewInputError("Vault provider " + v.Provider + " requires azure block") + } + case "google", "google-secret-manager": + if v.Google == nil { + return util.NewInputError("Vault provider " + v.Provider + " requires google block") + } + } return nil } @@ -678,9 +776,12 @@ func (exe remoteControlPlaneExecutor) transferControllerImages() error { return fmt.Errorf("failed to collect controller images: %w", err) } - // Transfer only controller image; router and debugger are needed in agent phase only. + // Transfer controller and NATS images (remote Controller runs/starts NATS). // Use platform and container engine from system agent config (validated when airgap is enabled). imageList := []string{images.Controller} + if images.Nats != "" { + imageList = append(imageList, images.Nats) + } controllers := remoteControlPlane.GetControllers() ctx := context.Background() @@ -767,11 +868,14 @@ func (exe remoteControlPlaneExecutor) transferSystemAgentImages() error { return fmt.Errorf("failed to get router image for platform %s: %w", platform, err) } - // Prepare image list (agent, router for platform, debugger if available) + // Prepare image list (agent, router for platform, NATS, debugger if available) imageList := []string{images.Agent} if routerImage != "" { imageList = append(imageList, routerImage) } + if images.Nats != "" { + imageList = append(imageList, images.Nats) + } if images.Debugger != "" { imageList = append(imageList, images.Debugger) } diff --git a/internal/deploy/execute.go b/internal/deploy/execute.go index 0a6d3b8..b63d87b 100644 --- a/internal/deploy/execute.go +++ b/internal/deploy/execute.go @@ -227,6 +227,14 @@ func Execute(opt *Options) (err error) { host := agentExecutor.GetHost() tags := agentExecutor.GetTags() deployConfig := agentExecutor.GetConfig() + + // Determine the host value to send to the Controller (AgentConfiguration.Host). + // Prefer the host explicitly set in the agent configuration; otherwise, fall back to the spec host. + apiHost := host + if deployConfig != nil && deployConfig.AgentConfiguration.Host != nil && *deployConfig.AgentConfiguration.Host != "" { + apiHost = *deployConfig.AgentConfiguration.Host + } + for _, configGenericExecutor := range executorsMap[config.AgentConfigKind] { configExecutor, ok := configGenericExecutor.(deployagentconfig.AgentConfigExecutor) if !ok { @@ -234,14 +242,14 @@ func Execute(opt *Options) (err error) { } if agentExecutor.GetName() == configExecutor.GetName() { found = true - configExecutor.SetHost(host) + configExecutor.SetHost(apiHost) configExecutor.SetTags(tags) break } } if !found { agentConfig := client.AgentConfiguration{ - Host: &host, + Host: &apiHost, } if util.IsLocalHost(host) && isLocalControlPlane { // Set de default local config to interior standalone for LocalControlPlane isSystem := true @@ -257,31 +265,37 @@ func Execute(opt *Options) (err error) { natsClusterPort := 6222 natsMqttPort := 8883 natsHttpPort := 8222 + jsStorageSize := "10G" + jsMemoryStoreSize := "1G" agentConfig.IsSystem = &isSystem agentConfig.DeploymentType = &deploymentType agentConfig.UpstreamRouters = &upstreamRouters - agentConfig.UpstreamNatsServers = &upstreamNatsServers agentConfig.RouterConfig = client.RouterConfig{ RouterMode: &routerMode, EdgeRouterPort: &edgeRouterPort, InterRouterPort: &interRouterPort, } - agentConfig.NatsMode = &natsMode - agentConfig.NatsServerPort = &natsServerPort - agentConfig.NatsLeafPort = &natsLeafPort - agentConfig.NatsClusterPort = &natsClusterPort - agentConfig.NatsMqttPort = &natsMqttPort - agentConfig.NatsHttpPort = &natsHttpPort + agentConfig.UpstreamNatsServers = &upstreamNatsServers + agentConfig.NatsConfig = client.NatsConfig{ + NatsMode: &natsMode, + NatsServerPort: &natsServerPort, + NatsLeafPort: &natsLeafPort, + NatsClusterPort: &natsClusterPort, + NatsMqttPort: &natsMqttPort, + NatsHttpPort: &natsHttpPort, + JsStorageSize: &jsStorageSize, + JsMemoryStoreSize: &jsMemoryStoreSize, + } } else { // For remote agents, use the configuration from the agent executor if deployConfig == nil { // Initialize default remote agent configuration agentConfig = client.AgentConfiguration{ - Host: &host, + Host: &apiHost, } } else { agentConfig = deployConfig.AgentConfiguration - agentConfig.Host = &host + agentConfig.Host = &apiHost } } executorsMap[config.AgentConfigKind] = append(executorsMap[config.AgentConfigKind], deployagentconfig.NewRemoteExecutor( diff --git a/internal/deploy/microservice/factory.go b/internal/deploy/microservice/factory.go index 3511c63..3030f6d 100644 --- a/internal/deploy/microservice/factory.go +++ b/internal/deploy/microservice/factory.go @@ -15,6 +15,7 @@ package deploymicroservice import ( "fmt" + "strings" apps "github.com/datasance/iofog-go-sdk/v3/pkg/apps" "github.com/datasance/potctl/internal/config" @@ -93,9 +94,18 @@ func NewExecutor(opt Options) (exe execute.Executor, err error) { return } + name := opt.Name + if !strings.Contains(name, "/") { + if m, ok := microservice.(map[interface{}]interface{}); ok { + if app, ok := m["application"].(string); ok && app != "" { + name = app + "/" + name + } + } + } + return &remoteExecutor{ namespace: opt.Namespace, microservice: µservice, - name: opt.Name, + name: name, }, nil } diff --git a/internal/deploy/natsaccountrule/factory.go b/internal/deploy/natsaccountrule/factory.go index 52f0e54..1ddb17f 100644 --- a/internal/deploy/natsaccountrule/factory.go +++ b/internal/deploy/natsaccountrule/factory.go @@ -22,7 +22,8 @@ type Options struct { type executor struct { namespace string name string - fullYAML []byte + specYAML []byte // spec-only payload sent to API (controller expects rule payload, not full doc) + fullYAML []byte // full doc used only for validation } func (exe *executor) GetName() string { @@ -36,7 +37,7 @@ func (exe *executor) Execute() error { return err } - reader := bytes.NewReader(exe.fullYAML) + reader := bytes.NewReader(exe.specYAML) _, err = clt.UpdateNatsAccountRuleFromYAML(exe.name, reader) if err == nil { return nil @@ -45,7 +46,7 @@ func (exe *executor) Execute() error { return err } - reader = bytes.NewReader(exe.fullYAML) + reader = bytes.NewReader(exe.specYAML) _, err = clt.CreateNatsAccountRuleFromYAML(reader) return err } @@ -65,17 +66,34 @@ func NewExecutor(opt Options) (execute.Executor, error) { // Validate YAML shape using strict decode against expected top-level fields. var validateDoc struct { - Kind config.Kind `yaml:"kind"` - Metadata config.HeaderMetadata `yaml:"metadata"` - Spec map[string]interface{} `yaml:"spec"` + APIVersion string `yaml:"apiVersion"` + Kind config.Kind `yaml:"kind"` + Metadata config.HeaderMetadata `yaml:"metadata"` + Spec map[string]interface{} `yaml:"spec"` } if err = yaml.UnmarshalStrict(opt.FullYAML, &validateDoc); err != nil { return nil, util.NewUnmarshalError(err.Error()) } + // Controller expects full document: apiVersion, kind, metadata, and spec (metadata and spec required). + specPayload := opt.Yaml + var specMap map[interface{}]interface{} + if err = yaml.Unmarshal(opt.Yaml, &specMap); err == nil { + doc := map[interface{}]interface{}{ + "apiVersion": "datasance.com/v3", + "kind": "NatsAccountRule", + "metadata": map[interface{}]interface{}{"name": opt.Name}, + "spec": specMap, + } + if specPayload, err = yaml.Marshal(doc); err != nil { + specPayload = opt.Yaml + } + } + return &executor{ namespace: opt.Namespace, name: opt.Name, + specYAML: specPayload, fullYAML: opt.FullYAML, }, nil } diff --git a/internal/deploy/natsuserrule/factory.go b/internal/deploy/natsuserrule/factory.go index 47cefe3..9af106e 100644 --- a/internal/deploy/natsuserrule/factory.go +++ b/internal/deploy/natsuserrule/factory.go @@ -22,7 +22,7 @@ type Options struct { type executor struct { namespace string name string - fullYAML []byte + specYAML []byte // spec-only payload sent to API (controller expects rule payload, not full doc) } func (exe *executor) GetName() string { @@ -36,7 +36,7 @@ func (exe *executor) Execute() error { return err } - reader := bytes.NewReader(exe.fullYAML) + reader := bytes.NewReader(exe.specYAML) _, err = clt.UpdateNatsUserRuleFromYAML(exe.name, reader) if err == nil { return nil @@ -45,7 +45,7 @@ func (exe *executor) Execute() error { return err } - reader = bytes.NewReader(exe.fullYAML) + reader = bytes.NewReader(exe.specYAML) _, err = clt.CreateNatsUserRuleFromYAML(reader) return err } @@ -65,17 +65,33 @@ func NewExecutor(opt Options) (execute.Executor, error) { // Validate YAML shape using strict decode against expected top-level fields. var validateDoc struct { - Kind config.Kind `yaml:"kind"` - Metadata config.HeaderMetadata `yaml:"metadata"` - Spec map[string]interface{} `yaml:"spec"` + APIVersion string `yaml:"apiVersion"` + Kind config.Kind `yaml:"kind"` + Metadata config.HeaderMetadata `yaml:"metadata"` + Spec map[string]interface{} `yaml:"spec"` } if err = yaml.UnmarshalStrict(opt.FullYAML, &validateDoc); err != nil { return nil, util.NewUnmarshalError(err.Error()) } + // Controller expects full document: apiVersion, kind, metadata, and spec (metadata and spec required). + specPayload := opt.Yaml + var specMap map[interface{}]interface{} + if err = yaml.Unmarshal(opt.Yaml, &specMap); err == nil { + doc := map[interface{}]interface{}{ + "apiVersion": "datasance.com/v3", + "kind": "NatsUserRule", + "metadata": map[interface{}]interface{}{"name": opt.Name}, + "spec": specMap, + } + if specPayload, err = yaml.Marshal(doc); err != nil { + specPayload = opt.Yaml + } + } + return &executor{ namespace: opt.Namespace, name: opt.Name, - fullYAML: opt.FullYAML, + specYAML: specPayload, }, nil } diff --git a/internal/deploy/serviceaccount/factory.go b/internal/deploy/serviceaccount/factory.go index 3055232..1c1e8b9 100644 --- a/internal/deploy/serviceaccount/factory.go +++ b/internal/deploy/serviceaccount/factory.go @@ -34,6 +34,7 @@ type Options struct { type executor struct { serviceAccount rsc.ServiceAccount namespace string + appName string name string } @@ -48,7 +49,7 @@ func (exe *executor) Execute() error { return err } - if _, err = clt.GetServiceAccount(exe.name); err != nil { + if _, err = clt.GetServiceAccount(exe.appName, exe.name); err != nil { return exe.createServiceAccount(clt) } return exe.updateServiceAccount(clt) @@ -56,8 +57,9 @@ func (exe *executor) Execute() error { func (exe *executor) createServiceAccount(clt *client.Client) error { req := &client.ServiceAccountCreateRequest{ - Name: exe.name, - RoleRef: toClientRoleRef(exe.serviceAccount.RoleRef), + Name: exe.name, + ApplicationName: exe.appName, + RoleRef: toClientRoleRef(exe.serviceAccount.RoleRef), } _, err := clt.CreateServiceAccount(req) return err @@ -68,7 +70,7 @@ func (exe *executor) updateServiceAccount(clt *client.Client) error { Name: exe.name, RoleRef: toClientRoleRef(exe.serviceAccount.RoleRef), } - _, err := clt.UpdateServiceAccount(exe.name, &req) + _, err := clt.UpdateServiceAccount(exe.appName, exe.name, &req) return err } @@ -101,10 +103,14 @@ func NewExecutor(opt Options) (execute.Executor, error) { if name == "" { return nil, util.NewInputError("Name must be specified") } + if sa.ApplicationName == "" { + return nil, util.NewInputError("ServiceAccount must have applicationName (application-scoped)") + } return &executor{ namespace: opt.Namespace, serviceAccount: sa, + appName: sa.ApplicationName, name: name, }, nil } diff --git a/internal/describe/serviceaccount.go b/internal/describe/serviceaccount.go index 6ee9b5f..390f0f0 100644 --- a/internal/describe/serviceaccount.go +++ b/internal/describe/serviceaccount.go @@ -14,6 +14,8 @@ package describe import ( + "strings" + "github.com/datasance/potctl/internal/config" rsc "github.com/datasance/potctl/internal/resource" clientutil "github.com/datasance/potctl/internal/util/client" @@ -22,19 +24,33 @@ import ( type serviceAccountExecutor struct { namespace string + appName string name string filename string } +// parseServiceAccountName returns (appName, name). Name can be "appName/name" or just "name" (appName then empty for list lookup). +func parseServiceAccountName(arg string) (appName, name string) { + if idx := strings.Index(arg, "/"); idx >= 0 { + return arg[:idx], arg[idx+1:] + } + return "", arg +} + func newServiceAccountExecutor(namespace, name, filename string) *serviceAccountExecutor { + appName, saName := parseServiceAccountName(name) return &serviceAccountExecutor{ namespace: namespace, - name: name, + appName: appName, + name: saName, filename: filename, } } func (exe *serviceAccountExecutor) GetName() string { + if exe.appName != "" { + return exe.appName + "/" + exe.name + } return exe.name } @@ -44,22 +60,28 @@ func (exe *serviceAccountExecutor) Execute() error { return err } - sa, err := clt.GetServiceAccount(exe.name) + if exe.appName == "" { + return util.NewInputError("ServiceAccount is application-scoped: use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa)") + } + + sa, err := clt.GetServiceAccount(exe.appName, exe.name) if err != nil { return err } spec := rsc.ServiceAccount{ - Name: sa.Name, - RoleRef: convertRoleRef(sa.RoleRef), + Name: sa.Name, + ApplicationName: sa.ApplicationName, + RoleRef: convertRoleRef(sa.RoleRef), } header := config.Header{ APIVersion: config.LatestAPIVersion, Kind: config.ServiceAccountKind, Metadata: config.HeaderMetadata{ - Namespace: exe.namespace, - Name: exe.name, + Namespace: exe.namespace, + Name: exe.name, + ApplicationName: sa.ApplicationName, }, Spec: spec, } diff --git a/internal/execute/utils.go b/internal/execute/utils.go index 7adbea8..33160ae 100644 --- a/internal/execute/utils.go +++ b/internal/execute/utils.go @@ -190,10 +190,11 @@ func headerDecodeToHeader(h *headerDecode) *config.Header { } case config.ServiceAccountKind: if h.RoleRef != nil { - // Controller-style: roleRef at top level + // Controller-style: metadata.applicationName and roleRef at top level header.Spec = map[string]interface{}{ - "name": h.Metadata.Name, - "roleRef": h.RoleRef, + "name": h.Metadata.Name, + "applicationName": h.Metadata.ApplicationName, + "roleRef": h.RoleRef, } } } diff --git a/internal/get/serviceaccount.go b/internal/get/serviceaccount.go index 41fffea..2d674eb 100644 --- a/internal/get/serviceaccount.go +++ b/internal/get/serviceaccount.go @@ -46,7 +46,7 @@ func generateServiceAccountsOutput(namespace string) error { return err } - list, err := clt.ListServiceAccounts() + list, err := clt.ListServiceAccounts("") if err != nil { return err } @@ -57,6 +57,7 @@ func generateServiceAccountsOutput(namespace string) error { func tabulateServiceAccounts(accounts []client.ServiceAccountInfo) error { table := make([][]string, len(accounts)+1) headers := []string{ + "APPLICATION", "NAME", "ROLE", } @@ -64,7 +65,9 @@ func tabulateServiceAccounts(accounts []client.ServiceAccountInfo) error { for idx, sa := range accounts { roleName := sa.RoleRef.Name + appName := sa.ApplicationName row := []string{ + appName, sa.Name, roleName, } diff --git a/internal/resource/k8s_controlplane.go b/internal/resource/k8s_controlplane.go index b375419..4c671b7 100644 --- a/internal/resource/k8s_controlplane.go +++ b/internal/resource/k8s_controlplane.go @@ -30,7 +30,8 @@ type KubernetesControlPlane struct { Endpoint string `yaml:"endpoint,omitempty"` Controller K8SControllerConfig `yaml:"controller,omitempty"` Ingresses Ingresses `yaml:"ingresses,omitempty"` - // Router RouterConfig `yaml:"router,omitempty"` + Nats *NatsSpec `yaml:"nats,omitempty"` + Vault *VaultSpec `yaml:"vault,omitempty"` } func (cp *KubernetesControlPlane) GetUser() IofogUser { @@ -148,16 +149,19 @@ func (cp *KubernetesControlPlane) Clone() ControlPlane { controllerPods := make([]KubernetesController, len(cp.ControllerPods)) copy(controllerPods, cp.ControllerPods) return &KubernetesControlPlane{ - KubeConfig: cp.KubeConfig, - IofogUser: cp.IofogUser, - Auth: cp.Auth, - Database: cp.Database, - Services: cp.Services, - Ingresses: cp.Ingresses, - // Router: cp.Router, + KubeConfig: cp.KubeConfig, + IofogUser: cp.IofogUser, + Auth: cp.Auth, + Database: cp.Database, + Events: cp.Events, + Services: cp.Services, + Ingresses: cp.Ingresses, Replicas: cp.Replicas, Images: cp.Images, Endpoint: cp.Endpoint, + Controller: cp.Controller, ControllerPods: controllerPods, + Nats: cp.Nats, + Vault: cp.Vault, } } diff --git a/internal/resource/local_controlplane.go b/internal/resource/local_controlplane.go index 5f62f16..a7e8359 100644 --- a/internal/resource/local_controlplane.go +++ b/internal/resource/local_controlplane.go @@ -18,11 +18,13 @@ import ( ) type LocalControlPlane struct { - IofogUser IofogUser `yaml:"iofogUser"` - Controller *LocalController `yaml:"controller,omitempty"` - Database Database `yaml:"database"` - Auth Auth `yaml:"auth"` - Events Events `yaml:"events,omitempty"` + IofogUser IofogUser `yaml:"iofogUser"` + Controller *LocalController `yaml:"controller,omitempty"` + Database Database `yaml:"database"` + Auth Auth `yaml:"auth"` + Events Events `yaml:"events,omitempty"` + SystemMicroservices *LocalSystemMicroservices `yaml:"systemMicroservices,omitempty"` + Nats *NatsEnabledConfig `yaml:"nats,omitempty"` } func (cp *LocalControlPlane) GetUser() IofogUser { @@ -94,10 +96,20 @@ func (cp *LocalControlPlane) Sanitize() error { } func (cp *LocalControlPlane) Clone() ControlPlane { + var sys *LocalSystemMicroservices + if cp.SystemMicroservices != nil { + sys = &LocalSystemMicroservices{ + Router: cp.SystemMicroservices.Router, + Nats: cp.SystemMicroservices.Nats, + } + } return &LocalControlPlane{ - IofogUser: cp.IofogUser, - Controller: cp.Controller.Clone().(*LocalController), - Database: cp.Database, - Auth: cp.Auth, + IofogUser: cp.IofogUser, + Controller: cp.Controller.Clone().(*LocalController), + Database: cp.Database, + Auth: cp.Auth, + Events: cp.Events, + SystemMicroservices: sys, + Nats: cp.Nats, } } diff --git a/internal/resource/remote_controlplane.go b/internal/resource/remote_controlplane.go index 713431d..b367ae4 100644 --- a/internal/resource/remote_controlplane.go +++ b/internal/resource/remote_controlplane.go @@ -28,6 +28,8 @@ type RemoteControlPlane struct { Events Events `yaml:"events,omitempty"` Package Package `yaml:"package,omitempty"` SystemMicroservices RemoteSystemMicroservices `yaml:"systemMicroservices,omitempty"` + Nats *NatsEnabledConfig `yaml:"nats,omitempty"` + Vault *VaultSpec `yaml:"vault,omitempty"` Endpoint string `yaml:"endpoint,omitempty"` Airgap bool `yaml:"airgap,omitempty"` } @@ -139,8 +141,11 @@ func (cp *RemoteControlPlane) Clone() ControlPlane { IofogUser: cp.IofogUser, Database: cp.Database, Auth: cp.Auth, + Events: cp.Events, Package: cp.Package, SystemMicroservices: cp.SystemMicroservices, + Nats: cp.Nats, + Vault: cp.Vault, Controllers: controllers, Endpoint: cp.Endpoint, Airgap: cp.Airgap, diff --git a/internal/resource/types.go b/internal/resource/types.go index 29de6b9..22a9604 100644 --- a/internal/resource/types.go +++ b/internal/resource/types.go @@ -53,21 +53,26 @@ type KubeImages struct { Controller string `yaml:"controller,omitempty"` Operator string `yaml:"operator,omitempty"` Router string `yaml:"router,omitempty"` + Nats string `yaml:"nats,omitempty"` } type Services struct { - Controller Service `json:"controller,omitempty"` - Router Service `json:"router,omitempty"` + Controller Service `json:"controller,omitempty" yaml:"controller,omitempty"` + Router Service `json:"router,omitempty" yaml:"router,omitempty"` + Nats Service `json:"nats,omitempty" yaml:"nats,omitempty"` + NatsServer Service `json:"natsServer,omitempty" yaml:"natsServer,omitempty"` } type Service struct { - Type string `json:"type,omitempty"` - Address string `json:"address,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` + Type string `json:"type,omitempty"` + Address string `json:"address,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` + ExternalTrafficPolicy string `json:"externalTrafficPolicy,omitempty" yaml:"externalTrafficPolicy,omitempty"` } type Replicas struct { Controller int32 `yaml:"controller"` + Nats int32 `yaml:"nats,omitempty"` } // Credentials credentials used to log into docker when deploying a local stack @@ -262,9 +267,79 @@ type Ingress struct { Address string `yaml:"address,omitempty"` } +// NatsIngress specifies the external address and ports for NATS hub (required when using ingress). +type NatsIngress struct { + Address string `yaml:"address,omitempty"` + ServerPort int `yaml:"serverPort,omitempty"` + ClusterPort int `yaml:"clusterPort,omitempty"` + LeafPort int `yaml:"leafPort,omitempty"` + MqttPort int `yaml:"mqttPort,omitempty"` + HttpPort int `yaml:"httpPort,omitempty"` +} + type Ingresses struct { Controller ControllerIngress `yaml:"controller,omitempty"` Router RouterIngress `yaml:"router,omitempty"` + Nats NatsIngress `yaml:"nats,omitempty"` +} + +// NatsJetStreamSpec configures JetStream storage (operator-compatible). +type NatsJetStreamSpec struct { + StorageSize string `yaml:"storageSize,omitempty"` + MemoryStoreSize string `yaml:"memoryStoreSize,omitempty"` + StorageClassName string `yaml:"storageClassName,omitempty"` +} + +// NatsSpec configures the NATS hub. When omitted, NATS is enabled with defaults. +type NatsSpec struct { + Enabled *bool `yaml:"enabled,omitempty"` + JetStream NatsJetStreamSpec `yaml:"jetStream,omitempty"` +} + +// VaultSpec configures vault integration for the Controller (Kubernetes and Remote). +type VaultSpec struct { + Enabled *bool `yaml:"enabled,omitempty"` + Provider string `yaml:"provider,omitempty"` + BasePath string `yaml:"basePath,omitempty"` + Hashicorp *VaultHashicorp `yaml:"hashicorp,omitempty"` + Aws *VaultAws `yaml:"aws,omitempty"` + Azure *VaultAzure `yaml:"azure,omitempty"` + Google *VaultGoogle `yaml:"google,omitempty"` +} + +type VaultHashicorp struct { + Address string `yaml:"address,omitempty"` + Token string `yaml:"token,omitempty"` + Mount string `yaml:"mount,omitempty"` +} + +type VaultAws struct { + Region string `yaml:"region,omitempty"` + AccessKeyId string `yaml:"accessKeyId,omitempty"` + AccessKey string `yaml:"accessKey,omitempty"` +} + +type VaultAzure struct { + URL string `yaml:"url,omitempty"` + TenantId string `yaml:"tenantId,omitempty"` + ClientId string `yaml:"clientId,omitempty"` + ClientSecret string `yaml:"clientSecret,omitempty"` +} + +type VaultGoogle struct { + ProjectId string `yaml:"projectId,omitempty"` + Credentials string `yaml:"credentials,omitempty"` +} + +// LocalSystemMicroservices holds optional system image overrides for local control plane. +type LocalSystemMicroservices struct { + Router string `yaml:"router,omitempty"` + Nats string `yaml:"nats,omitempty"` +} + +// NatsEnabledConfig is the NATS config for remote and local control planes (enabling only; no service/ingress/jetStream). +type NatsEnabledConfig struct { + Enabled *bool `yaml:"enabled,omitempty"` } // type RouterConfig struct { @@ -316,9 +391,11 @@ type RoleBinding struct { Subjects []Subject `yaml:"subjects,omitempty"` } +// ServiceAccount is application-scoped; Controller identifies it by (applicationName, name). type ServiceAccount struct { - Name string `yaml:"name,omitempty"` - RoleRef RoleRef `yaml:"roleRef,omitempty"` + Name string `yaml:"name,omitempty"` + ApplicationName string `yaml:"applicationName,omitempty"` + RoleRef RoleRef `yaml:"roleRef,omitempty"` } type ClusterService struct { diff --git a/internal/util/client/api.go b/internal/util/client/api.go index 60081e4..47ea7e0 100644 --- a/internal/util/client/api.go +++ b/internal/util/client/api.go @@ -195,14 +195,34 @@ func GetAgentConfig(agentName, namespace string) (agentConfig rsc.AgentConfigura if agentInfo.UpstreamRouters != nil { upstreamRouters := []string{} for _, upstreamRouterAgentUUID := range *agentInfo.UpstreamRouters { - upstreamRouters = append(upstreamRouters, getAgentNameFromUUID(agentMapByUUID, upstreamRouterAgentUUID)) + upstreamRouters = append(upstreamRouters, getRouterAgentNameFromUUID(agentMapByUUID, upstreamRouterAgentUUID)) } upstreamRoutersPtr = &upstreamRouters } + natsConfig := client.NatsConfig{ + NatsMode: agentInfo.NatsMode, + NatsServerPort: agentInfo.NatsServerPort, + NatsLeafPort: agentInfo.NatsLeafPort, + NatsClusterPort: agentInfo.NatsClusterPort, + NatsMqttPort: agentInfo.NatsMqttPort, + NatsHttpPort: agentInfo.NatsHttpPort, + JsStorageSize: agentInfo.JsStorageSize, + JsMemoryStoreSize: agentInfo.JsMemoryStoreSize, + } + + var upstreamNatsServersPtr *[]string + if agentInfo.UpstreamNatsServers != nil { + upstreamNatsServers := []string{} + for _, upstreamNatsServerUUID := range *agentInfo.UpstreamNatsServers { + upstreamNatsServers = append(upstreamNatsServers, getNatsAgentNameFromUUID(agentMapByUUID, upstreamNatsServerUUID)) + } + upstreamNatsServersPtr = &upstreamNatsServers + } + var networkRouterPtr *string if agentInfo.NetworkRouter != nil { - networkRouter := getAgentNameFromUUID(agentMapByUUID, *agentInfo.NetworkRouter) + networkRouter := getRouterAgentNameFromUUID(agentMapByUUID, *agentInfo.NetworkRouter) networkRouterPtr = &networkRouter } @@ -241,16 +261,9 @@ func GetAgentConfig(agentName, namespace string) (agentConfig rsc.AgentConfigura UpstreamRouters: upstreamRoutersPtr, NetworkRouter: networkRouterPtr, RouterConfig: routerConfig, + UpstreamNatsServers: upstreamNatsServersPtr, + NatsConfig: natsConfig, TimeZone: agentInfo.TimeZone, - NatsMode: agentInfo.NatsMode, - NatsServerPort: agentInfo.NatsServerPort, - NatsLeafPort: agentInfo.NatsLeafPort, - NatsClusterPort: agentInfo.NatsClusterPort, - NatsMqttPort: agentInfo.NatsMqttPort, - NatsHttpPort: agentInfo.NatsHttpPort, - JsStorageSize: agentInfo.JsStorageSize, - JsMemoryStoreSize: agentInfo.JsMemoryStoreSize, - UpstreamNatsServers: agentInfo.UpstreamNatsServers, }, } diff --git a/internal/util/client/client.go b/internal/util/client/client.go index a386813..d2d9dcf 100644 --- a/internal/util/client/client.go +++ b/internal/util/client/client.go @@ -302,7 +302,7 @@ func getBackendAgents(namespace string, ioClient *client.Client) ([]client.Agent return agentList.Agents, nil } -func getAgentNameFromUUID(agentMapByUUID map[string]client.AgentInfo, uuid string) (name string) { +func getRouterAgentNameFromUUID(agentMapByUUID map[string]client.AgentInfo, uuid string) (name string) { // if uuid == iofog.VanillaRemoteAgentName { // return uuid // } @@ -319,6 +319,21 @@ func getAgentNameFromUUID(agentMapByUUID map[string]client.AgentInfo, uuid strin return } +func getNatsAgentNameFromUUID(agentMapByUUID map[string]client.AgentInfo, uuid string) (name string) { + + if uuid == iofog.VanillaNatsAgentName { + return uuid + } + agent, found := agentMapByUUID[uuid] + if !found { + util.PrintNotify(fmt.Sprintf("Could not find NATS: %s\n", uuid)) + name = "UNKNOWN NATS: " + uuid + } else { + name = agent.Name + } + return +} + // isAuthenticationError checks if an error is an authentication/authorization error func isAuthenticationError(err error) bool { if err == nil { diff --git a/pkg/iofog/constants.go b/pkg/iofog/constants.go index a6f7b54..562bac2 100644 --- a/pkg/iofog/constants.go +++ b/pkg/iofog/constants.go @@ -28,6 +28,7 @@ const ( // VanillaRemoteAgentName string = "0-controlplane" VanillaRouterAgentName string = client.DefaultRouterName + VanillaNatsAgentName string = client.DefaultNatsServerName VanillaLocalAgentName string = "local-agent" // RouterMode values diff --git a/pkg/iofog/install/controller.go b/pkg/iofog/install/controller.go index 5e22cc4..d0a4cb7 100644 --- a/pkg/iofog/install/controller.go +++ b/pkg/iofog/install/controller.go @@ -38,19 +38,20 @@ type RemoteSystemImages struct { type RemoteSystemMicroservices struct { Router RemoteSystemImages `yaml:"router,omitempty"` + Nats RemoteSystemImages `yaml:"nats,omitempty"` } type ControllerOptions struct { - User string - Host string - Port int - Namespace string - PrivKeyFilename string - Version string - Image string - // Repo string - // Token string + User string + Host string + Port int + Namespace string + PrivKeyFilename string + Version string + Image string SystemMicroservices RemoteSystemMicroservices + NatsEnabled *bool // NATS enabling for remote control plane (nil = default enabled) + Vault *VaultConfig PidBaseDir string EcnViewerPort int EcnViewerURL string @@ -513,6 +514,85 @@ func (ctrl *Controller) prepareEnvironmentVariables() string { if ctrl.SystemMicroservices.Router.ARM != "" { env = append(env, fmt.Sprintf("\"ROUTER_IMAGE_2=%s\"", ctrl.SystemMicroservices.Router.ARM)) } + natsX86 := ctrl.SystemMicroservices.Nats.X86 + natsARM := ctrl.SystemMicroservices.Nats.ARM + if natsX86 == "" && natsARM != "" { + natsX86 = natsARM + } + if natsARM == "" && natsX86 != "" { + natsARM = natsX86 + } + if natsX86 == "" && natsARM == "" { + natsX86 = util.GetNatsImage() + natsARM = natsX86 + } + if natsX86 != "" { + env = append(env, fmt.Sprintf("\"NATS_IMAGE_1=%s\"", natsX86)) + } + if natsARM != "" { + env = append(env, fmt.Sprintf("\"NATS_IMAGE_2=%s\"", natsARM)) + } + // NATS enabling (remote/local control plane: only enabling parameter) + natsEnabled := true + if ctrl.NatsEnabled != nil { + natsEnabled = *ctrl.NatsEnabled + } + env = append(env, fmt.Sprintf("\"NATS_ENABLED=%t\"", natsEnabled)) + if ctrl.Vault != nil { + if ctrl.Vault.Enabled != nil { + env = append(env, fmt.Sprintf("\"VAULT_ENABLED=%t\"", *ctrl.Vault.Enabled)) + } + if ctrl.Vault.Provider != "" { + env = append(env, fmt.Sprintf("\"VAULT_PROVIDER=%s\"", ctrl.Vault.Provider)) + } + if ctrl.Vault.BasePath != "" { + env = append(env, fmt.Sprintf("\"VAULT_BASE_PATH=%s\"", ctrl.Vault.BasePath)) + } + if ctrl.Vault.Hashicorp != nil { + if ctrl.Vault.Hashicorp.Address != "" { + env = append(env, fmt.Sprintf("\"VAULT_HASHICORP_ADDRESS=%s\"", ctrl.Vault.Hashicorp.Address)) + } + if ctrl.Vault.Hashicorp.Token != "" { + env = append(env, fmt.Sprintf("\"VAULT_HASHICORP_TOKEN=%s\"", ctrl.Vault.Hashicorp.Token)) + } + if ctrl.Vault.Hashicorp.Mount != "" { + env = append(env, fmt.Sprintf("\"VAULT_HASHICORP_MOUNT=%s\"", ctrl.Vault.Hashicorp.Mount)) + } + } + if ctrl.Vault.Aws != nil { + if ctrl.Vault.Aws.Region != "" { + env = append(env, fmt.Sprintf("\"VAULT_AWS_REGION=%s\"", ctrl.Vault.Aws.Region)) + } + if ctrl.Vault.Aws.AccessKeyId != "" { + env = append(env, fmt.Sprintf("\"VAULT_AWS_ACCESS_KEY_ID=%s\"", ctrl.Vault.Aws.AccessKeyId)) + } + if ctrl.Vault.Aws.AccessKey != "" { + env = append(env, fmt.Sprintf("\"VAULT_AWS_ACCESS_KEY=%s\"", ctrl.Vault.Aws.AccessKey)) + } + } + if ctrl.Vault.Azure != nil { + if ctrl.Vault.Azure.URL != "" { + env = append(env, fmt.Sprintf("\"VAULT_AZURE_URL=%s\"", ctrl.Vault.Azure.URL)) + } + if ctrl.Vault.Azure.TenantId != "" { + env = append(env, fmt.Sprintf("\"VAULT_AZURE_TENANT_ID=%s\"", ctrl.Vault.Azure.TenantId)) + } + if ctrl.Vault.Azure.ClientId != "" { + env = append(env, fmt.Sprintf("\"VAULT_AZURE_CLIENT_ID=%s\"", ctrl.Vault.Azure.ClientId)) + } + if ctrl.Vault.Azure.ClientSecret != "" { + env = append(env, fmt.Sprintf("\"VAULT_AZURE_CLIENT_SECRET=%s\"", ctrl.Vault.Azure.ClientSecret)) + } + } + if ctrl.Vault.Google != nil { + if ctrl.Vault.Google.ProjectId != "" { + env = append(env, fmt.Sprintf("\"VAULT_GOOGLE_PROJECT_ID=%s\"", ctrl.Vault.Google.ProjectId)) + } + if ctrl.Vault.Google.Credentials != "" { + env = append(env, fmt.Sprintf("\"VAULT_GOOGLE_CREDENTIALS=%s\"", ctrl.Vault.Google.Credentials)) + } + } + } if ctrl.LogLevel != "" { env = append(env, fmt.Sprintf("\"LOG_LEVEL=%s\"", ctrl.LogLevel)) } diff --git a/pkg/iofog/install/k8s.go b/pkg/iofog/install/k8s.go index 15cacf2..5c5682c 100644 --- a/pkg/iofog/install/k8s.go +++ b/pkg/iofog/install/k8s.go @@ -113,6 +113,14 @@ func (k8s *Kubernetes) SetControllerImage(image string) { } } +func (k8s *Kubernetes) SetNatsImage(image string) { + if image != "" { + k8s.images.Nats = image + } else { + k8s.images.Nats = util.GetNatsImage() + } +} + func (k8s *Kubernetes) SetPullSecret(pullSecret string) { if pullSecret != "" { k8s.images.PullSecret = pullSecret @@ -228,6 +236,9 @@ func (k8s *Kubernetes) CreateControlPlane(conf *K8SControllerConfig) (endpoint s // Set specification cp.Spec.Replicas.Controller = conf.Replicas + if conf.ReplicasNats >= 2 { + cp.Spec.Replicas.Nats = conf.ReplicasNats + } cp.Spec.Database = cpv3.Database(conf.Database) cp.Spec.Auth = cpv3.Auth(conf.Auth) cp.Spec.Events = cpv3.Events(conf.Events) @@ -235,6 +246,12 @@ func (k8s *Kubernetes) CreateControlPlane(conf *K8SControllerConfig) (endpoint s cp.Spec.Services = k8s.services cp.Spec.Ingresses = k8s.ingresses cp.Spec.Images = k8s.images + if conf.Nats != nil { + cp.Spec.Nats = conf.Nats + } + if conf.Vault != nil { + cp.Spec.Vault = conf.Vault + } // cp.Spec.Router = k8s.router cp.Spec.Controller.EcnViewerPort = conf.EcnViewerPort cp.Spec.Controller.EcnViewerURL = conf.EcnViewerURL @@ -669,7 +686,7 @@ func (k8s *Kubernetes) handleLoadBalancer(svc *corev1.Service, targetPort int32) return } -func (k8s *Kubernetes) SetControllerService(svcType, address string, annotations map[string]string) { +func (k8s *Kubernetes) SetControllerService(svcType, address string, annotations map[string]string, externalTrafficPolicy string) { if svcType != "" { k8s.services.Controller.Type = svcType } else { @@ -677,9 +694,10 @@ func (k8s *Kubernetes) SetControllerService(svcType, address string, annotations } k8s.services.Controller.Address = address k8s.services.Controller.Annotations = annotations + k8s.services.Controller.ExternalTrafficPolicy = externalTrafficPolicy } -func (k8s *Kubernetes) SetRouterService(svcType, address string, annotations map[string]string) { +func (k8s *Kubernetes) SetRouterService(svcType, address string, annotations map[string]string, externalTrafficPolicy string) { if svcType != "" { k8s.services.Router.Type = svcType } else { @@ -687,6 +705,7 @@ func (k8s *Kubernetes) SetRouterService(svcType, address string, annotations map } k8s.services.Router.Address = address k8s.services.Router.Annotations = annotations + k8s.services.Router.ExternalTrafficPolicy = externalTrafficPolicy } func (k8s *Kubernetes) SetControllerIngress(annotations map[string]string, ingressClassName string, host string, secretName string) { @@ -703,6 +722,37 @@ func (k8s *Kubernetes) SetRouterIngress(address string, messagePort int, interio k8s.ingresses.Router.EdgePort = edgePort } +func (k8s *Kubernetes) SetNatsService(svcType, address string, annotations map[string]string, externalTrafficPolicy string) { + if svcType != "" { + k8s.services.Nats.Type = svcType + } else { + k8s.services.Nats.Type = string(corev1.ServiceTypeClusterIP) + } + k8s.services.Nats.Address = address + k8s.services.Nats.Annotations = annotations + k8s.services.Nats.ExternalTrafficPolicy = externalTrafficPolicy +} + +func (k8s *Kubernetes) SetNatsServerService(svcType, address string, annotations map[string]string, externalTrafficPolicy string) { + if svcType != "" { + k8s.services.NatsServer.Type = svcType + } else { + k8s.services.NatsServer.Type = string(corev1.ServiceTypeLoadBalancer) + } + k8s.services.NatsServer.Address = address + k8s.services.NatsServer.Annotations = annotations + k8s.services.NatsServer.ExternalTrafficPolicy = externalTrafficPolicy +} + +func (k8s *Kubernetes) SetNatsIngress(address string, serverPort, clusterPort, leafPort, mqttPort, httpPort int) { + k8s.ingresses.Nats.Address = address + k8s.ingresses.Nats.ServerPort = serverPort + k8s.ingresses.Nats.ClusterPort = clusterPort + k8s.ingresses.Nats.LeafPort = leafPort + k8s.ingresses.Nats.MqttPort = mqttPort + k8s.ingresses.Nats.HttpPort = httpPort +} + // func (k8s *Kubernetes) SetRouterConfig(HA *bool) { // k8s.router.HA = HA diff --git a/pkg/iofog/install/k8s_microservices.go b/pkg/iofog/install/k8s_microservices.go index 2d783d1..b890403 100644 --- a/pkg/iofog/install/k8s_microservices.go +++ b/pkg/iofog/install/k8s_microservices.go @@ -103,6 +103,7 @@ func newOperatorMicroservice() *microservice { }, Resources: []string{ "deployments", + "statefulsets", }, Verbs: []string{ "*", diff --git a/pkg/iofog/install/local_container.go b/pkg/iofog/install/local_container.go index ffa3648..3c5462c 100644 --- a/pkg/iofog/install/local_container.go +++ b/pkg/iofog/install/local_container.go @@ -144,7 +144,7 @@ func NewLocalAgentConfig(name, image string, ctrlConfig *LocalContainerConfig, c "iofog-agent-log:/var/log/iofog-agent:rw", "iofog-agent-backup:/var/backups/iofog-agent:rw", "iofog-agent-version:/usr/share/iofog-agent:rw", - "iofog-agent-directory:/var/lib/iofog-agent:rw", + "/var/lib/iofog-agent:/var/lib/iofog-agent:rw", // "/sbin/shutdown:/sbin/shutdown", }, Envs: []string{ @@ -157,8 +157,15 @@ func NewLocalAgentConfig(name, image string, ctrlConfig *LocalContainerConfig, c } } +// LocalSystemImages optionally sets Router and Nats images and NATS enabling for the local controller. +type LocalSystemImages struct { + Router string + Nats string + NatsEnabled *bool // nil = default enabled +} + // NewLocalControllerConfig generats a static controller config -func NewLocalControllerConfig(image string, credentials Credentials, auth Auth, db Database, events Events) *LocalContainerConfig { +func NewLocalControllerConfig(image string, credentials Credentials, auth Auth, db Database, events Events, systemImages *LocalSystemImages) *LocalContainerConfig { if image == "" { image = util.GetControllerImage() } @@ -213,6 +220,24 @@ func NewLocalControllerConfig(image string, credentials Credentials, auth Auth, } } + if systemImages != nil { + if systemImages.Router != "" { + envs = append(envs, "ROUTER_IMAGE_1="+systemImages.Router, "ROUTER_IMAGE_2="+systemImages.Router) + } + natsImg := systemImages.Nats + if natsImg == "" { + natsImg = util.GetNatsImage() + } + if natsImg != "" { + envs = append(envs, "NATS_IMAGE_1="+natsImg, "NATS_IMAGE_2="+natsImg) + } + natsEnabled := true + if systemImages.NatsEnabled != nil { + natsEnabled = *systemImages.NatsEnabled + } + envs = append(envs, fmt.Sprintf("NATS_ENABLED=%t", natsEnabled)) + } + return &LocalContainerConfig{ Host: "0.0.0.0", Ports: []port{ diff --git a/pkg/iofog/install/types.go b/pkg/iofog/install/types.go index 92519ea..6a44a7c 100644 --- a/pkg/iofog/install/types.go +++ b/pkg/iofog/install/types.go @@ -13,6 +13,10 @@ package install +import ( + cpv3 "github.com/datasance/iofog-operator/v3/apis/controlplanes/v3" +) + type IofogUser struct { Name string Surname string @@ -51,6 +55,41 @@ type Events struct { CaptureIpAddress *bool } +// VaultConfig is used by the remote controller install to pass VAULT_* env vars (operator-compatible shape). +type VaultConfig struct { + Enabled *bool + Provider string + BasePath string + Hashicorp *VaultHashicorpConfig + Aws *VaultAwsConfig + Azure *VaultAzureConfig + Google *VaultGoogleConfig +} + +type VaultHashicorpConfig struct { + Address string + Token string + Mount string +} + +type VaultAwsConfig struct { + Region string + AccessKeyId string + AccessKey string +} + +type VaultAzureConfig struct { + URL string + TenantId string + ClientId string + ClientSecret string +} + +type VaultGoogleConfig struct { + ProjectId string + Credentials string +} + type Pod struct { Name string Status string @@ -59,6 +98,7 @@ type Pod struct { type K8SControllerConfig struct { // User IofogUser Replicas int32 + ReplicasNats int32 Database Database PidBaseDir string EcnViewerPort int @@ -68,4 +108,6 @@ type K8SControllerConfig struct { Events Events Https *bool SecretName string + Nats *cpv3.Nats + Vault *cpv3.Vault } diff --git a/pkg/util/version.go b/pkg/util/version.go index 67650b4..ad7c49f 100644 --- a/pkg/util/version.go +++ b/pkg/util/version.go @@ -28,6 +28,7 @@ var ( agentTag = "undefined" operatorTag = "undefined" routerTag = "undefined" + natsTag = "undefined" controllerVersion = "undefined" agentVersion = "undefined" debuggerTag = "undefined" @@ -39,6 +40,7 @@ const ( operatorImage = "operator" routerImage = "router" routerARMImage = "router" + natsImage = "nats" debuggerImage = "node-debugger" ) @@ -68,4 +70,5 @@ func GetAgentImage() string { return fmt.Sprintf("%s/%s:%s", repo, agentImag func GetOperatorImage() string { return fmt.Sprintf("%s/%s:%s", repo, operatorImage, operatorTag) } func GetRouterImage() string { return fmt.Sprintf("%s/%s:%s", repo, routerImage, routerTag) } func GetRouterARMImage() string { return fmt.Sprintf("%s/%s:%s", repo, routerARMImage, routerTag) } +func GetNatsImage() string { return fmt.Sprintf("%s/%s:%s", repo, natsImage, natsTag) } func GetDebuggerImage() string { return fmt.Sprintf("%s/%s:%s", repo, debuggerImage, debuggerTag) }