diff --git a/docs/index.md b/docs/index.md index 26cf4a2..5b18aff 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,9 +16,9 @@ With Kele, you can: - Manage [contexts], e.g. [switching, renaming, changing the default namespace](./how-tos/usage.md#contexts); -- [Fetch and display the manifest of a single - resource](./how-tos/usage.md#working-with-resources); -- [Follow logs for a single resource](./how-tos/usage.md#following-logs) +- [Display details](./how-tos/usage.md#working-with-resources), [follow + logs](./how-tos/usage.md#following-logs), and manage port-forwards for + resources; - [List collections of resources](./how-tos/usage.md#working-with-resources); - Start and stop [proxy servers](./how-tos/usage.md#managing-proxy-servers); - Use the menu bar to perform basic cluster/config management; diff --git a/docs/references/changelog.md b/docs/references/changelog.md index f578e02..56563c6 100644 --- a/docs/references/changelog.md +++ b/docs/references/changelog.md @@ -18,6 +18,8 @@ versioning][semver]. similar to `kubectl get deployments` - `kele-resource` now has a keybinding to follow logs for resources that support it +- `kele-resource` now has a suffix for port-forwarding to resources that support + it ## 0.6.0 diff --git a/kele.el b/kele.el index ba79a8f..0bb9f35 100644 --- a/kele.el +++ b/kele.el @@ -110,6 +110,9 @@ pods." (defvar kele--loggable-kinds '("pods" "deployments" "jobs" "services") "Resource kinds that can be passed to kubectl log.") +(defvar kele--port-forwardable-kinds '("pods" "deployments" "services") + "Resource kinds that can be passed to kubectl port-forward.") + ;; TODO (#80): Display in the `kele-get-mode' header what fields were filtered out (defcustom kele-filtered-fields '((metadata managedFields) (metadata annotations kubectl.kubernetes.io/last-applied-configuration)) @@ -567,6 +570,16 @@ GROUP and VERSION are not always set. KIND is always set." (concat (oref gvk group) "/" vk) vk))) +(cl-defmethod kele--singular ((gvk kele--gvk) &optional context) + "Return the name of GVK in singular form. + +If CONTEXT is provided, look up in that context. Otherwise, use +the current context." + (kele--get-singular-for-plural + kele--global-discovery-cache + (oref gvk kind) + :context (or context (kele-current-context-name)))) + (cl-defstruct (kele--proxy-record (:constructor kele--proxy-record-create) (:copier nil)) @@ -1992,6 +2005,57 @@ to query for." (list (kele--get-context-arg) ns gvk name))) (kele--render-object (kele--get-resource gvk name :namespace namespace :context context))) +(transient-define-suffix kele-port-forward (context namespace gvk name port) + "Create a port-forward for resource GVK named NAME at PORT. + +NAMESPACE and CONTEXT are used to identify the resource type to query for." + :key "F" + :description + "Port-forward to..." + :if + (lambda () + (let-alist (oref transient--prefix scope) + (-contains? kele--port-forwardable-kinds .kind))) + (interactive + (let* ((gvk (kele--get-gvk-arg)) + (context (kele--get-context-arg)) + (ns (kele--get-namespace-arg + :kind (oref gvk kind) + :group-version (kele--gv-string gvk) + :use-default nil)) + (cands (kele--fetch-resource-names gvk :namespace ns :context context)) + (name (completing-read + (format "%s to port-forward to: " (kele--singular gvk)) + (-cut kele--resources-complete <> <> <> :cands cands))) + + ;; TODO: Completion on the resource's exposed ports + ;; TODO: Error if the port is already in use + (port (number-to-string (read-number "Port: ")))) + (list context ns gvk name port))) + (let ((proc-name (format "kele: port-forward (%s/%s, %s, %s, %s)" (oref gvk kind) name context namespace port))) + (make-process + :name proc-name + :command (list kele-kubectl-executable + "--context" + context + "--namespace" + namespace + "port-forward" + (format "%s/%s" (oref gvk kind) name) + port) + :buffer (generate-new-buffer (format " *%s*" proc-name)) + :sentinel + (lambda (proc _status) + (let ((exit-code (process-exit-status proc))) + (cl-case exit-code + (0 (message "Successfully terminated port-forward for %s" name)) + (9 (message "Port-forward for %s (port %s) terminated" name port)) + (t (message "Port-forward process for %s failed with exit code %s" name exit-code))) + (kele--kill-process-quietly proc))) + :noquery t)) + (message "[kele] Started port-forward for %s/%s (port %s)" (oref gvk kind) name port)) + + (transient-define-suffix kele-deployment-restart (context namespace deployment-name) "Restart DEPLOYMENT-NAME. @@ -2043,6 +2107,7 @@ CONTEXT and NAMESPACE are used to identify where the deployment lives." (propertize it 'face 'warning)) (propertize "-specific actions" 'face 'transient-heading)))) (kele-resource-follow-logs) + (kele-port-forward) (kele-deployment-restart)]] (interactive (let* ((context (kele-current-context-name))