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.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..f58ff28 --- /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. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa). + +``` +potctl delete serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME [flags] +``` + +### Examples + +``` +potctl delete serviceaccount myapp/my-sa +``` + +### 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..38d513c --- /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. ServiceAccounts are application-scoped; use APPLICATION_NAME/SERVICE_ACCOUNT_NAME (e.g. myapp/my-sa). + +``` +potctl describe serviceaccount APPLICATION_NAME/SERVICE_ACCOUNT_NAME [flags] +``` + +### Examples + +``` +potctl describe serviceaccount myapp/my-sa +``` + +### 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..5033144 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 + 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 - 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..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.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 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= @@ -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/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.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/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/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..0cd9d10 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" @@ -63,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/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/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 21b69a2..20b6cb8 100644 --- a/internal/deploy/agentconfig/utils.go +++ b/internal/deploy/agentconfig/utils.go @@ -24,10 +24,15 @@ import ( type RouterMode string +type NatsMode string + const ( EdgeRouter RouterMode = "edge" InteriorRouter RouterMode = "interior" NoneRouter RouterMode = "none" + NatsNone NatsMode = "none" + NatsLeaf NatsMode = "leaf" + NatsServer NatsMode = "server" ) func getRouterMode(config *rsc.AgentConfiguration) RouterMode { @@ -37,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" @@ -56,6 +69,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 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)) + } return nil } @@ -99,6 +116,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/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/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..b63d87b 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) @@ -211,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 { @@ -218,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 @@ -234,6 +258,15 @@ 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 + jsStorageSize := "10G" + jsMemoryStoreSize := "1G" agentConfig.IsSystem = &isSystem agentConfig.DeploymentType = &deploymentType agentConfig.UpstreamRouters = &upstreamRouters @@ -242,16 +275,27 @@ func Execute(opt *Options) (err error) { EdgeRouterPort: &edgeRouterPort, InterRouterPort: &interRouterPort, } + 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 || deployConfig.AgentConfiguration == (client.AgentConfiguration{}) { + 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( @@ -331,12 +375,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 +469,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 +524,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 +538,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 +546,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/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 new file mode 100644 index 0000000..1ddb17f --- /dev/null +++ b/internal/deploy/natsaccountrule/factory.go @@ -0,0 +1,99 @@ +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 + 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 { + 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.specYAML) + _, err = clt.UpdateNatsAccountRuleFromYAML(exe.name, reader) + if err == nil { + return nil + } + if _, ok := err.(*client.NotFoundError); !ok { + return err + } + + reader = bytes.NewReader(exe.specYAML) + _, 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 { + 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 new file mode 100644 index 0000000..9af106e --- /dev/null +++ b/internal/deploy/natsuserrule/factory.go @@ -0,0 +1,97 @@ +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 + specYAML []byte // spec-only payload sent to API (controller expects rule payload, not full doc) +} + +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.specYAML) + _, err = clt.UpdateNatsUserRuleFromYAML(exe.name, reader) + if err == nil { + return nil + } + if _, ok := err.(*client.NotFoundError); !ok { + return err + } + + reader = bytes.NewReader(exe.specYAML) + _, 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 { + 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, + specYAML: specPayload, + }, 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/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/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/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/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..33160ae 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 } @@ -184,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/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/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/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/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 67c079f..22a9604 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 @@ -54,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 @@ -263,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 { @@ -317,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 e2669ff..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,6 +261,8 @@ func GetAgentConfig(agentName, namespace string) (agentConfig rsc.AgentConfigura UpstreamRouters: upstreamRoutersPtr, NetworkRouter: networkRouterPtr, RouterConfig: routerConfig, + UpstreamNatsServers: upstreamNatsServersPtr, + NatsConfig: natsConfig, TimeZone: agentInfo.TimeZone, }, } 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 8c8e89b..562bac2 100644 --- a/pkg/iofog/constants.go +++ b/pkg/iofog/constants.go @@ -28,8 +28,10 @@ const ( // VanillaRemoteAgentName string = "0-controlplane" VanillaRouterAgentName string = client.DefaultRouterName + VanillaNatsAgentName string = client.DefaultNatsServerName VanillaLocalAgentName string = "local-agent" // RouterMode values RouterModeInterior string = "interior" + NatsModeServer string = "server" ) diff --git a/pkg/iofog/install/controller.go b/pkg/iofog/install/controller.go index 9bc22c1..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)) } @@ -630,13 +710,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 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) }