From: Andreas Gerler Date: Sun, 26 Apr 2026 17:56:38 +0000 (+0200) Subject: update kubed X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=b0d48e726ad9f05b729246cb602352d68feaeb79;p=emacsconfig.git update kubed --- diff --git a/elpa/kubed-0.5.0.signed b/elpa/kubed-0.5.0.signed deleted file mode 100644 index 6bef68e9..00000000 --- a/elpa/kubed-0.5.0.signed +++ /dev/null @@ -1 +0,0 @@ -Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) (trust undefined) created at 2025-06-11T23:05:01+0200 using EDDSA \ No newline at end of file diff --git a/elpa/kubed-0.5.0/.elpaignore b/elpa/kubed-0.5.0/.elpaignore deleted file mode 100644 index afa5a63e..00000000 --- a/elpa/kubed-0.5.0/.elpaignore +++ /dev/null @@ -1,5 +0,0 @@ -.dir-locals.el -README.md -kubed.png -explain-and-patch.png -pod-context-menu.png diff --git a/elpa/kubed-0.5.0/LICENSE b/elpa/kubed-0.5.0/LICENSE deleted file mode 100644 index cfd527c4..00000000 --- a/elpa/kubed-0.5.0/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2024-2025 Eshel Yaron - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/elpa/kubed-0.5.0/NEWS.org b/elpa/kubed-0.5.0/NEWS.org deleted file mode 100644 index c8dd79ad..00000000 --- a/elpa/kubed-0.5.0/NEWS.org +++ /dev/null @@ -1,156 +0,0 @@ -#+title: Kubed NEWS -- history of user-visible changes -#+author: Eshel Yaron -#+email: me@eshelyaron.com -#+language: en -#+options: ':t toc:nil num:nil ^:{} - -This file contains the release notes for Kubed, a rich Emacs interface -for Kubernetes. - -For further details, see the Kubed manual: -[[https://eshelyaron.com/kubed.html][https://eshelyaron.com/kubed.html]]. - -* Version 0.5.0 on 2025-06-11 - -** DaemonSets support - -Kubed now provides commands for working with DaemonSets by default. -Remember that you can always configure support for additional resource -types with the ~kubed-define-resource~ macro! - -** Fix Tramp integration for context names with non-alphanumeric characters - -This version fixes an issue in the Kubed integration with Tramp, which -caused it to fail for ~kubectl~ contexts whose name includes ":" and -most other non-alphanumeric characters. - -See bug report at https://lists.sr.ht/~eshel/kubed-devel/%3C87ldqz70a6.fsf@gmail.com%3E - -* Version 0.4.3 on 2025-01-21 - -This is a maintenance release, it includes minor improvements and one -important bug fix: - -** Fix 'kubed-list-delete-marked' in non-default context - -Marking resources with ~d~ and deleting them with ~x~ now works also -in resource tables of resources in non-default contexts or namespaces. - -* Version 0.4.2 on 2024-10-22 - -** New user option 'kubed-list-mode-line-format' - -This user option lets you customize the indicator that Kubed shows in -the mode line of resource table buffers when update is in progress. - -** Fix Tramp method autoload issue - -This version arranges for the Kubed Tramp integration to be loaded -earlier, which circumvents the "Method ‘kubedv1’ is not known" error -that some users have experienced. - -* Version 0.4.1 on 2024-09-23 - -** New command and transient menu for scaling deployments - -You can now scale Kubernetes deployment with Kubed, directly with -~kubed-scale-deployment~, from the deployments table buffer, or via -the new transient menu ~kubed-transient-scale-deployment~. - -** New commands and transient menu for managing Kubernetes API proxies - -You can now use Kubed to create proxy servers that give access to the -Kubernetes API server. The commands ~kubed-proxy~ and -~kubed-stop-proxy~ start and stop proxy servers, respectively. The -new transient menu ~kubed-transient-proxy~ lets specify options when -starting a proxy, such as the local port to use. - -* Version 0.4.0 on 2024-08-23 - -** ~kubed-list-update~ is now bound to ~g~ in resource table buffers. - -Previously, this command was bound to the slightly less convenient -capital ~G~. This shadows the default binding of ~revert-buffer~, -which you can still invoke via ~C-x x g~. - -** Introduce resource type specific bindings in resource table help transients. - -The help transient menu that you get with ~?~ in resource table -buffers now includes type-specific bindings, such as the ~F~ key for -forwarding a local port to a pod in the Kubed pods buffer. - -** New transient menu ~kubed-transient-logs~ for showing container logs. - -** Improved Tramp integration. - -Kubed now uses a bespoke Tramp method to open Dired and Shell buffers -inside Kubernetes pods. The main advantage of this method is the -ability to work with multiple ~kubectl~ contexts simultaneously. This -method requires Tramp 2.7 or later, Kubed will complain if you try to -start remote Dired or Shell with an earlier Tramp version. - -* Version 0.3.2 on 2024-08-15 - -** Improved support for multiple contexts and namespaces - -Each buffer now has a local context and namespace, which acts as the -default/current context and namespace when you invoke Kubed commands -from that buffer. See new manual section "Context and Namespace" for -more details. - -** New filter operators ~<~ and ~>~ in resource tables. - -These operators let you filter line with columns that are less than or -greater than a given value. - -** New command for applying changes to displayed resource. - -You can now edit displayed resource YAML buffers after you select a -resource with ~RET~ in the table buffer, and apply your changes to the -live resource with ~C-c C-c~. - -* Version 0.3.1 on 2024-08-06 - -** New command for fitting column width to content in resource tables. - -** New transient menu showing help in resource table buffers. - -* Version 0.3.0 on 2024-08-05 - -** New command for copying name of resource at point to kill ring. - -** New commands for running ~kubectl~ command on resource at point. - -** Support bookmarking resource list and resource details buffers. - -** New command for jumping from resource details buffer to list buffer. - -** Fix installation on Doom Emacs. - -** New transient menu for displaying resources. - -** Support multiple resource list buffers with different namespaces or contexts. - -* Version 0.2.0 on 2024-08-02 - -** Ensure compatibility with Emacs 29. - -** Add right-click context menus in resource tables. - -** New menu-bar "Kubernetes" menu. - -** New commands for restarting and watching deployments. - -** Add filtering capability to all resource tables. - -** New cron job commands: suspend, resume, and start job now. - -** New commands for patching resources. - -** New useful columns in services table and deployments table. - -** Use multi-column layout in transient menus. - -* Version 0.1.0 on 2024-07-28 - -Initial release. diff --git a/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png b/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png deleted file mode 100644 index 19551b12..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-list-transient.png b/elpa/kubed-0.5.0/assets/kubed-list-transient.png deleted file mode 100644 index c0fdb281..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-list-transient.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-overview.png b/elpa/kubed-0.5.0/assets/kubed-overview.png deleted file mode 100644 index b74db912..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-overview.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-prefix-map.png b/elpa/kubed-0.5.0/assets/kubed-prefix-map.png deleted file mode 100644 index 0f0d6090..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-prefix-map.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-replace-diff.png b/elpa/kubed-0.5.0/assets/kubed-replace-diff.png deleted file mode 100644 index 6e6d07a1..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-replace-diff.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png b/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png deleted file mode 100644 index 3f51ecd3..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-transient-exec.png b/elpa/kubed-0.5.0/assets/kubed-transient-exec.png deleted file mode 100644 index 5f412e8e..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-transient-exec.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/assets/kubed-transient.png b/elpa/kubed-0.5.0/assets/kubed-transient.png deleted file mode 100644 index 97fa375f..00000000 Binary files a/elpa/kubed-0.5.0/assets/kubed-transient.png and /dev/null differ diff --git a/elpa/kubed-0.5.0/cobra.el b/elpa/kubed-0.5.0/cobra.el deleted file mode 100644 index c7d5ffb0..00000000 --- a/elpa/kubed-0.5.0/cobra.el +++ /dev/null @@ -1,143 +0,0 @@ -;;; cobra.el --- Complete Cobra command lines -*- lexical-binding: t; -*- - -;; Copyright (C) 2024-2025 Free Software Foundation, Inc. - -;; Author: Eshel Yaron -;; Keywords: tools - -;;; Commentary: - -;; Cobra is a popular Golang framework for CLI programs. This library -;; defines function `cobra-read-command-line', which helps you read a -;; command line for a program that uses Cobra, with completion. -;; Prominent examples of Cobra programs are `kubectl' and `docker'. - -;;; Code: - -(defvar cobra--cache nil) - -(defun cobra-completion-table (executable s p a) - "Completion table for command lines that invoke EXECUTABLE. - -Perform completion action A on string S with predicate P." - (let ((start 0)) - (while (string-match "[[:space:]=]" s start) - (setq start (match-end 0))) - (if (eq a 'metadata) - `(metadata - (category . cobra-command-line) - (affixation-function - . ,(lambda (cands) - (let ((max (seq-max - (cons 0 (mapcar #'string-width cands))))) - (mapcar - (lambda (cand) - (list - cand "" - (if-let - ((desc (get-text-property - 0 'cobra-argument-description - cand))) - (concat - (make-string (1+ (- max (string-width cand))) ?\s) - (propertize desc 'face 'completions-annotations)) - ""))) - cands))))) - (let* ((lines - (cdr - (if (string= s (car cobra--cache)) - ;; Cache hit. - cobra--cache - (setq - cobra--cache - (cons s - (apply #'process-lines-ignore-status - executable "__complete" - (let ((args (cdr (split-string-and-unquote s)))) - (if (string-suffix-p " " s) - ;; Restore omitted empty argument. - (nconc args '("")) - args)))))))) - (code nil) - (comps (seq-take-while - (lambda (line) - (not (and (string-match "^:\\([0-9]+\\)$" line) - (setq code (string-to-number - (match-string 1 line)))))) - lines))) - ;; `code' encodes "completion directives", as follows: - ;; #b000001: An error occurred, ignore completions. - ;; #b000010: Don't add space after completion. (TODO.) - ;; #b000100: Don't fall back to file completion. - ;; #b001000: Completions are really file extension filters. - ;; #b010000: Complete directory names. - ;; #b100000: Preserve completions order. - (when (and code (zerop (logand 1 code))) - ;; Error bit in unset, proceed. - (if (= #b100 (logand #b100 code)) - ;; No file name completion. - (if (eq (car-safe a) 'boundaries) - `(boundaries - ,start . ,(and (string-match "[[:space:]=]" (cdr a)) - (match-beginning 0))) - (let ((table - (mapcar - ;; Annotate completion candidates. - (lambda (comp) - (pcase (split-string comp "\t" t) - (`(,c ,d . ,_) - (propertize - c 'cobra-argument-description - ;; Only keep first sentence. - (car (split-string d "\\." t)))) - (`(,c . ,_) c))) - comps))) - (if a (complete-with-action a table (substring s start) p) - ;; `try-completion'. - (let ((comp (complete-with-action a table (substring s start) p))) - (if (stringp comp) (concat (substring s 0 start) comp) comp))))) - ;; File name completion. - (setq p - (cond - ((= #b1000 (logand #b1000 code)) - ;; `comps' are valid extensions. - (lambda (f) - (or (file-directory-p f) - (when (string-match "\\.[^.]*\\'" f) - (member (substring f (1+ (match-beginning 0))) - comps))))) - ((= #b10000 (logand #b10000 code)) - ;; Directory name completion. - #'file-directory-p))) - (if (eq (car-safe a) 'boundaries) - ;; Find nested boundaries. - (let* ((suf (cdr a)) - (bounds (completion-boundaries - (substring s start) #'completion-file-name-table p - (substring suf 0 (string-match "[[:space:]=]" suf))))) - `(boundaries ,(+ (car bounds) start) . ,(cdr bounds))) - (if a (complete-with-action a #'completion-file-name-table - (substring s start) p) - (let ((comp (complete-with-action a #'completion-file-name-table - (substring s start) p))) - (if (stringp comp) (concat (substring s 0 start) comp) comp)))))))))) - -;;;###autoload -(defun cobra-read-command-line (prompt initial &optional hist) - "Prompt with PROMPT for a command line starting with INITIAL. - -Optional argument HIST is the name of the history list variable to use, -if it is nil or omitted, it defaults to `shell-command-history'." - (let ((exec (car (split-string-and-unquote (car (ensure-list initial)))))) - (minibuffer-with-setup-hook - (:append (lambda () - (let ((map (make-sparse-keymap))) - ;; Ensure SPC is self-inserting. - (keymap-unset map "SPC") - (use-local-map - (make-composed-keymap map (current-local-map)))))) - (completing-read prompt (apply-partially #'cobra-completion-table exec) - nil nil initial (or hist 'shell-command-history))))) - -(provide 'cobra) -;;; cobra.el ends here diff --git a/elpa/kubed-0.5.0/dir b/elpa/kubed-0.5.0/dir deleted file mode 100644 index c2a31044..00000000 --- a/elpa/kubed-0.5.0/dir +++ /dev/null @@ -1,18 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Kubed: (kubed). Kubernetes, Emacs, done! diff --git a/elpa/kubed-0.5.0/kubed-autoloads.el b/elpa/kubed-0.5.0/kubed-autoloads.el deleted file mode 100644 index e7274907..00000000 --- a/elpa/kubed-0.5.0/kubed-autoloads.el +++ /dev/null @@ -1,509 +0,0 @@ -;;; kubed-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from cobra.el - -(autoload 'cobra-read-command-line "cobra" "\ -Prompt with PROMPT for a command line starting with INITIAL. - -Optional argument HIST is the name of the history list variable to use, -if it is nil or omitted, it defaults to `shell-command-history'. - -(fn PROMPT INITIAL &optional HIST)") -(register-definition-prefixes "cobra" '("cobra-")) - - -;;; Generated autoloads from kubed.el - -(autoload 'kubed-display-resource "kubed" "\ -Display Kubernetes RESOURCE of type TYPE in CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCE. With a prefix argument \\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well. - -(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t) -(autoload 'kubed-display-resource-handle-bookmark "kubed" "\ -Display Kubernetes resource according to BOOKMARK. - -(fn BOOKMARK)") -(autoload 'kubed-list-handle-bookmark "kubed" "\ -Display Kubernetes resource according to BOOKMARK. - -(fn BOOKMARK)") -(autoload 'kubed-delete-resources "kubed" "\ -Delete Kubernetes RESOURCES of type TYPE in context CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCES. With a prefix argument \\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well. - -(fn TYPE RESOURCES CONTEXT &optional NAMESPACE)" t) -(autoload 'kubed-edit-resource "kubed" "\ -Edit Kubernetes RESOURCE of type TYPE in context CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCES. With a prefix argument \\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well. - -(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t) -(autoload 'kubed-define-resource "kubed" "\ -Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS. - -RESOURCE is a symbol corresponding to a Kubernetes resource type, such -as `pod' or `service'. This macro defines the following commands for -interacting with Kubernetes RESOURCEs: - -- `kubed-display-RESOURCE': prompt for a RESOURCE and display its - description in YAML format. See also `kubed-yaml-setup-hook'. -- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it. -- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it. -- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the - current namespace. The RESOURCEs list buffer uses a dedicated major - mode, `kubed-RESOURCEs-mode', which is also defined by this macro. -- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file. -- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs. - -This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map', -with bindings for the above commands. - -PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS) -that specify properties of RESOURCEs. PROP is the name of the property, -as a symbol; JSON-PATH is a JSONPath expression that evaluates to the -value of PROP when applied to the JSON representation of a RESOURCE. -WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted. WIDTH is -used as the default width of the column corresponding to PROP in -RESOURCEs list buffers; SORT is sort predicate, a function that takes -two values of PROP as strings and returns non-nil if the first should -sort before the second; FORMAT is a function that takes a value of PROP -and formats it. If you provide a FORMAT function and a SORT function, -then the SORT function gets the formatted values (the output of the -FORMAT function), not the original values. If you want to sort based on -the unformatted original values, you can store them as text properties -in your FORMAT function and access them in your SORT function. - -ATTRS is a plist of additional attributes of the PROP column, see -`tabulated-list-format' for available attributes. - -For example, if PROPERTIES is (phase \".status.phase\" 10) that means -that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose -values are typically 10 columns wide. The first property in PROPERTIES -is used to annotate completion candidates when prompting for a RESOURCE. - -COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that -define commands for RESOURCE list buffers. COMMAND is a symbol -specifying the suffix of the command name, the full name of the command -is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is -either a string that specifies a key sequence to bind to the command in -`kubed-RESOURCEs-mode-map', or nil if the command should not be bound; -DOC-PREFIX is a string used to construct the docstring of the command, -this macro appends the string \" Kubernetes RESOURCE at point.\" to it -to obtain the final docstring; lastly, BODY is the body the command. -Within BODY, the variable RESOURCE is let-bound to the name of the -RESOURCE at point. For example, if RESOURCE is `pod', the following -COMMANDS element defines a command `kubed-pods-frob' and binds it to the -key \"f\" in `kubed-pods-mode-map': - - (frob \"f\" \"Frobnicate\" - (message \"Preparing...\") - (frobnicate-pod pod) - (message \"Done.\")) - -By default, this macro assumes that RESOURCE is namespaced. To define a -namespaceless resource type, put `:namespaced nil' before COMMANDS: - - (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil - CMD1 - CMD2 - ...) - -Other keyword arguments that go between PROPERTIES and COMMANDS are: - -- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the - resource creation command, `kubed-create-RESOURCE'. ARGLIST, - DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'. -- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the - prefix keymap `kubed-RESOURCE-prefix-map' and the - `kubed-RESOURCE-menu-map' menu. Each element (KEY LABEL DEFINITION) - says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to - add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL. -- `:plural PLURAL': specify plural form of RESOURCE, as a symbol. If - you omit this keyword argument, the plural form defaults to RESOURCE - followed by \"s\". -- `:logs t': generate `kubed-logs-for-RESOURCE' command. -- `:suffixes (SUFFIX...)': add type-specific transient suffixes to - `kubed-list-transient'. - -(fn RESOURCE &optional PROPERTIES &rest COMMANDS)" nil t) -(function-put 'kubed-define-resource 'lisp-indent-function 2) - (autoload 'kubed-display-pod "kubed" nil t) - (autoload 'kubed-edit-pod "kubed" nil t) - (autoload 'kubed-delete-pods "kubed" nil t) - (autoload 'kubed-list-pods "kubed" nil t) - (autoload 'kubed-create-pod "kubed" nil t) - (autoload 'kubed-logs-for-pod "kubed" nil t) - (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-namespace "kubed" nil t) - (autoload 'kubed-edit-namespace "kubed" nil t) - (autoload 'kubed-delete-namespaces "kubed" nil t) - (autoload 'kubed-list-namespaces "kubed" nil t) - (autoload 'kubed-create-namespace "kubed" nil t) - (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-persistentvolume "kubed" nil t) - (autoload 'kubed-edit-persistentvolume "kubed" nil t) - (autoload 'kubed-delete-persistentvolumes "kubed" nil t) - (autoload 'kubed-list-persistentvolumes "kubed" nil t) - (autoload 'kubed-create-persistentvolume "kubed" nil t) - (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-service "kubed" nil t) - (autoload 'kubed-edit-service "kubed" nil t) - (autoload 'kubed-delete-services "kubed" nil t) - (autoload 'kubed-list-services "kubed" nil t) - (autoload 'kubed-create-service "kubed" nil t) - (autoload 'kubed-logs-for-service "kubed" nil t) - (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-secret "kubed" nil t) - (autoload 'kubed-edit-secret "kubed" nil t) - (autoload 'kubed-delete-secrets "kubed" nil t) - (autoload 'kubed-list-secrets "kubed" nil t) - (autoload 'kubed-create-secret "kubed" nil t) - (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-job "kubed" nil t) - (autoload 'kubed-edit-job "kubed" nil t) - (autoload 'kubed-delete-jobs "kubed" nil t) - (autoload 'kubed-list-jobs "kubed" nil t) - (autoload 'kubed-create-job "kubed" nil t) - (autoload 'kubed-logs-for-job "kubed" nil t) - (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap) -(autoload 'kubed-watch-deployment-status "kubed" "\ -Show and update status of Kubernetes deployment DEP in a dedicate buffer. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. CB is an optional callback function to call with -no arguments when the deployment ends. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. - -(fn DEP &optional CONTEXT NAMESPACE CB)" t) -(autoload 'kubed-scale-deployment "kubed" "\ -Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. - -(fn DEP REPS &optional CONTEXT NAMESPACE)" t) -(autoload 'kubed-restart-deployment "kubed" "\ -Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. CB is an optional callback function to call with -no arguments when the deployment ends. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. - -(fn DEP &optional CONTEXT NAMESPACE)" t) - (autoload 'kubed-display-deployment "kubed" nil t) - (autoload 'kubed-edit-deployment "kubed" nil t) - (autoload 'kubed-delete-deployments "kubed" nil t) - (autoload 'kubed-list-deployments "kubed" nil t) - (autoload 'kubed-create-deployment "kubed" nil t) - (autoload 'kubed-logs-for-deployment "kubed" nil t) - (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-replicaset "kubed" nil t) - (autoload 'kubed-edit-replicaset "kubed" nil t) - (autoload 'kubed-delete-replicasets "kubed" nil t) - (autoload 'kubed-list-replicasets "kubed" nil t) - (autoload 'kubed-create-replicaset "kubed" nil t) - (autoload 'kubed-logs-for-replicaset "kubed" nil t) - (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-daemonset "kubed" nil t) - (autoload 'kubed-edit-daemonset "kubed" nil t) - (autoload 'kubed-delete-daemonsets "kubed" nil t) - (autoload 'kubed-list-daemonsets "kubed" nil t) - (autoload 'kubed-create-daemonset "kubed" nil t) - (autoload 'kubed-logs-for-daemonset "kubed" nil t) - (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-statefulset "kubed" nil t) - (autoload 'kubed-edit-statefulset "kubed" nil t) - (autoload 'kubed-delete-statefulsets "kubed" nil t) - (autoload 'kubed-list-statefulsets "kubed" nil t) - (autoload 'kubed-create-statefulset "kubed" nil t) - (autoload 'kubed-logs-for-statefulset "kubed" nil t) - (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-cronjob "kubed" nil t) - (autoload 'kubed-edit-cronjob "kubed" nil t) - (autoload 'kubed-delete-cronjobs "kubed" nil t) - (autoload 'kubed-list-cronjobs "kubed" nil t) - (autoload 'kubed-create-cronjob "kubed" nil t) - (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-ingressclass "kubed" nil t) - (autoload 'kubed-edit-ingressclass "kubed" nil t) - (autoload 'kubed-delete-ingressclasses "kubed" nil t) - (autoload 'kubed-list-ingressclasss "kubed" nil t) - (autoload 'kubed-create-ingressclass "kubed" nil t) - (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap) - (autoload 'kubed-display-ingress "kubed" nil t) - (autoload 'kubed-edit-ingress "kubed" nil t) - (autoload 'kubed-delete-ingresses "kubed" nil t) - (autoload 'kubed-list-ingresss "kubed" nil t) - (autoload 'kubed-create-ingress "kubed" nil t) - (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap) -(autoload 'kubed-use-context "kubed" "\ -Set current Kubernetes context to CONTEXT. - -(fn CONTEXT)" t) -(autoload 'kubed-rename-context "kubed" "\ -Rename Kubernetes context OLD to NEW. - -(fn OLD NEW)" t) -(autoload 'kubed-display-config "kubed" "\ -Display current Kubernetes client settings in a YAML buffer." t) -(autoload 'kubed-set-namespace "kubed" "\ -Set default Kubernetes namespace in CONTEXT to NAMESPACE. - -Interactively, prompt for NAMESPACE and use the current context. With a -prefix argument, prompt for CONTEXT as well. - -(fn NAMESPACE &optional CONTEXT)" t) -(autoload 'kubed-apply "kubed" "\ -Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT. - -(fn CONFIG &optional KIND CONTEXT)" t) -(autoload 'kubed-create "kubed" "\ -Create resource of kind KIND with definition DEFINITION via CONTEXT. - -(fn DEFINITION &optional KIND CONTEXT)" t) -(autoload 'kubed-run "kubed" "\ -Run container IMAGE in a new Kubernetes POD. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context. NAMESPACE is the namespace in which to create POD, -defaulting to the current namespace. PORT is the port to expose, -defaulting to none. If ATTACH is non-nil, then attach to the created -image with a `comint-mode' buffer, and pop to that buffer. Non-nil -STDIN says to keep the standard input of the container open; non-nil TTY -says to allocate a TTY for the container; and non-nil RM says to remove -the container after it exits. ENVS is a list of strings \"VAR=VAL\" -which specify environment variables VAR and values VAL to give them in -the created container. ARGS are command line arguments for the -container command. If COMMAND is non-nil, ARGS consist of a complete -command line, that overrides the container command instead of just -providing it with arguments. - -Interactively, prompt for POD and IMAGE. With a prefix argument, prompt -for NAMESPACE; with a double prefix argument, also prompt for CONTEXT. - -(fn POD IMAGE &optional CONTEXT NAMESPACE PORT ATTACH STDIN TTY RM ENVS COMMAND ARGS)" t) -(autoload 'kubed-logs "kubed" "\ -Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE. - -Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is -the namespace for RESOURCE; CONTAINER is the name of the container in -RESOURCE to show logs for, or t which specifies all relevant containers. - -With a prefix argument, prompt for NAMESPACE; with a double prefix -argument, also prompt for CONTEXT. - -(fn TYPE RESOURCE &optional CONTEXT NAMESPACE CONTAINER FOLLOW LIMIT PREFIX SINCE TAIL TIMESTAMPS)" t) -(autoload 'kubed-forward-port-to-pod "kubed" "\ -Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD. - -(fn POD LOCAL-PORT REMOTE-PORT CONTEXT NAMESPACE)" t) -(autoload 'kubed-attach "kubed" "\ -Attach to running process in CONTAINER in Kubernetes POD. - -Optional argument NAMESPACE is the namespace in which to look for POD. -Non-nil STDIN says to connect local standard input to remote process. -Non-nil TTY says to use a TTY for standard input. - -Interactively, prompt for POD; if there are multiple pod containers, -prompt for CONTAINER as well. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. -STDIN and TTY are t interactively. - -(fn POD &optional CONTAINER CONTEXT NAMESPACE STDIN TTY)" t) -(autoload 'kubed-diff "kubed" "\ -Display difference between Kubernetes resource DEFINITION and current state. - -DEFINITION is either a file name or a buffer. Interactively, prompt for -a YAML or JSON file name to use as DEFINITION. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; non-nil INCLUDE-MANAGED (interactively, the prefix -argument) says to include managed fields in the comparison. - -(fn DEFINITION &optional INCLUDE-MANAGED CONTEXT)" t) -(autoload 'kubed-exec "kubed" "\ -Execute COMMAND with ARGS in CONTAINER in Kubernetes POD. - -Optional argument NAMESPACE is the namespace in which to look for POD. -Non-nil STDIN says to connect local standard input to remote process. -Non-nil TTY says to use a TTY for standard input. - -Interactively, prompt for POD; if there are multiple pod containers, -prompt for CONTAINER as well. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. -STDIN and TTY are t interactively. - -(fn POD COMMAND &optional CONTAINER CONTEXT NAMESPACE STDIN TTY ARGS)" t) -(autoload 'kubed-patch "kubed" "\ -Patch Kubernetes resource NAME of TYPE with patch PATCH. - -Optional argument NAMESPACE is the namespace in which to look for NAME. -STRATEGY is the patch type to use, one of \"json\", \"merge\" and -\"strategic\", defaulting to \"strategic\". - -Interactively, prompt for TYPE, NAME and PATCH. With a prefix argument, -prompt for NAMESPACE too. With a double prefix argument, also prompt -for CONTEXT. - -(fn TYPE NAME PATCH &optional CONTEXT NAMESPACE STRATEGY)" t) -(autoload 'kubed-proxy "kubed" "\ -Start a web server on localhost proxying the Kubernetes API server. - -ADDR and PORT are the local address and port to bind the proxy server -to. They default to 127.0.0.1 and 8001, respectively. API-PREFIX is a -prefix under which to proxy the Kubernetes API. WWW-DIR is a local -directory to serve under WWW-PREFIX, which defaults to \"/static/\". -Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the -local context. - -(fn &optional ADDR PORT API-PREFIX WWW-DIR WWW-PREFIX CONTEXT)" t) -(autoload 'kubed-stop-proxy "kubed" "\ -Stop local proxy for context CONTEXT, defaulting to the local context. - -(fn &optional CONTEXT)" t) -(autoload 'kubed-explain "kubed" "\ -Show help buffer with explanation about Kubernetes resource FIELD. - -(fn FIELD)" t) -(autoload 'kubed-kubectl-command "kubed" "\ -Execute `kubectl' COMMAND. - -This function calls `shell-command' (which see) to do the work. - -Interactively, prompt for COMMAND with completion for `kubectl' arguments. - -(fn COMMAND)" t) - (autoload 'kubed-prefix-map "kubed" nil t 'keymap) -(defvar kubed-menu-bar-mode nil "\ -Non-nil if Kubed-Menu-Bar mode is enabled. -See the `kubed-menu-bar-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `kubed-menu-bar-mode'.") -(custom-autoload 'kubed-menu-bar-mode "kubed" nil) -(autoload 'kubed-menu-bar-mode "kubed" "\ -Add \"Kubernetes\" menu to your menu bar. - -This is a global minor mode. If called interactively, toggle the -`Kubed-Menu-Bar mode' mode. If the prefix argument is positive, enable -the mode, and if it is zero or negative, disable the mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable the -mode if ARG is nil, omitted, or is a positive number. Disable the mode -if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate `(default-value \\='kubed-menu-bar-mode)'. - -The mode's hook is called both when the mode is enabled and when it is -disabled. - -(fn &optional ARG)" t) -(register-definition-prefixes "kubed" '("kubed-")) - - -;;; Generated autoloads from kubed-common.el - -(register-definition-prefixes "kubed-common" '("kubed-")) - - -;;; Generated autoloads from kubed-tramp.el - -(autoload 'kubed-tramp-context "kubed-tramp" "\ -Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME. - -(fn FILE-NAME)") -(autoload 'kubed-tramp-namespace "kubed-tramp" "\ -Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME. - -(fn FILE-NAME)") -(autoload 'kubed-tramp-assert-support "kubed-tramp" "\ -Check if Kubed Tramp support is available, throw `user-error' if not.") -(autoload 'kubed-tramp-enable "kubed-tramp" "\ -Enable Kubed integration with Tramp.") - (with-eval-after-load 'tramp (kubed-tramp-enable)) -(register-definition-prefixes "kubed-tramp" '("kubed-tramp--")) - - -;;; Generated autoloads from kubed-transient.el - - (autoload 'kubed-transient "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t) - (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t) - (autoload 'kubed-transient-logs "kubed-transient" nil t) - (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t) - (autoload 'kubed-transient-proxy "kubed-transient" nil t) - (autoload 'kubed-transient-rollout "kubed-transient" nil t) - (autoload 'kubed-transient-attach "kubed-transient" nil t) - (autoload 'kubed-transient-diff "kubed-transient" nil t) - (autoload 'kubed-transient-exec "kubed-transient" nil t) - (autoload 'kubed-transient-run "kubed-transient" nil t) - (autoload 'kubed-transient-apply "kubed-transient" nil t) - (autoload 'kubed-transient-patch "kubed-transient" nil t) - (autoload 'kubed-transient-create "kubed-transient" nil t) - (autoload 'kubed-transient-display "kubed-transient" nil t) - (autoload 'kubed-transient-edit "kubed-transient" nil t) - (autoload 'kubed-transient-delete "kubed-transient" nil t) - (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t) - (autoload 'kubed-transient-create-ingress "kubed-transient" nil t) - (autoload 'kubed-transient-create-deployment "kubed-transient" nil t) - (autoload 'kubed-transient-create-job "kubed-transient" nil t) - (autoload 'kubed-list-transient "kubed-transient" nil t) -(register-definition-prefixes "kubed-transient" '("kubed-transient-")) - -;;; End of scraped data - -(provide 'kubed-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; kubed-autoloads.el ends here diff --git a/elpa/kubed-0.5.0/kubed-common.el b/elpa/kubed-0.5.0/kubed-common.el deleted file mode 100644 index f7cb240e..00000000 --- a/elpa/kubed-0.5.0/kubed-common.el +++ /dev/null @@ -1,25 +0,0 @@ -;;; kubed-common.el --- Common definitons for Kubed -*- lexical-binding: t; -*- - -;; Copyright (C) 2024-2025 Free Software Foundation, Inc. - -;; Author: Eshel Yaron -;; Keywords: tools - -;;; Commentary: - -;; This library provides definitions that both `kubed' and `kubed-tramp' -;; require. - -;;; Code: - -(defvar kubed-tramp-method "kubedv2" ;Versioned, for compatibility. - ;; (find-file "/kubedv2:CONTEXT%NAMESPACE%POD%CONTAINER:/some/file") - "Name of the Kubed Tramp method.") - -(defcustom kubed-kubectl-program "kubectl" - "Name of `kubectl' executable to use for interacting with Kubernetes." - :type 'string - :group 'kubed) - -(provide 'kubed-common) -;;; kubed-tramp.el ends here diff --git a/elpa/kubed-0.5.0/kubed-pkg.el b/elpa/kubed-0.5.0/kubed-pkg.el deleted file mode 100644 index 9717f71b..00000000 --- a/elpa/kubed-0.5.0/kubed-pkg.el +++ /dev/null @@ -1,2 +0,0 @@ -;; Generated package description from kubed.el -*- mode: lisp-data; no-byte-compile: t -*- -(define-package "kubed" "0.5.0" "Kubernetes, Emacs, done!" '((emacs "29.1")) :commit "e8a6f9b0dc25d44f3783036962d6c08eacbdbd23" :authors '(("Eshel Yaron" . "me@eshelyaron.com")) :maintainer '("Eshel Yaron" . "~eshel/kubed-devel@lists.sr.ht") :keywords '("tools" "kubernetes" "containers") :url "https://eshelyaron.com/kubed.html") diff --git a/elpa/kubed-0.5.0/kubed-tramp.el b/elpa/kubed-0.5.0/kubed-tramp.el deleted file mode 100644 index 9e6fbac4..00000000 --- a/elpa/kubed-0.5.0/kubed-tramp.el +++ /dev/null @@ -1,150 +0,0 @@ -;;; kubed-tramp.el --- Kubed Tramp integration -*- lexical-binding: t; -*- - -;; Copyright (C) 2024-2025 Free Software Foundation, Inc. - -;; Author: Eshel Yaron -;; Keywords: tools - -;;; Commentary: - -;; This library provides Tramp integration for Kubed. This is similar -;; to the built-in "kubernetes" Tramp method from tramp-container.el, -;; except that the Kubed method always requires the container name and -;; Kubernetes namespace to be specified, as well a `kubectl' context. -;; In other words, the filename syntax of this method is fully explicit. -;; An explicit syntax is useful when juggling between different contexts -;; and namespaces with Kubed; on the other hand, for finding a remote -;; file with C-x C-f, the concise syntax of the built-in "kubernetes" -;; method is probably more convenient. - -;;; Code: - -(require 'kubed-common) -(require 'tramp) - -(defun kubed-tramp--unhex (x) - ;; Simplified version of `url-unhex'. - (if (> x ?9) (+ 10 (- x ?A)) (- x ?0))) - -(defun kubed-tramp--decode-context-name (str) - ;; Adopted from `url-unhex-string'. - (let ((tmp "") (case-fold-search nil)) - (while (string-match "[.][0-9A-F][0-9A-F]" str) - (let* ((start (match-beginning 0)) - (ch1 (kubed-tramp--unhex (elt str (+ start 1)))) - (code (+ (* 16 ch1) - (kubed-tramp--unhex (elt str (+ start 2)))))) - (setq tmp (concat tmp (substring str 0 start) (byte-to-string code)) - str (substring str (match-end 0))))) - (concat tmp str))) - -(defun kubed-tramp--v2-context (vec) - "Extract the context name from a kubernetes host name in VEC." - (or (when-let ((host (and vec (tramp-file-name-host vec)))) - (shell-quote-argument - (decode-coding-string - (kubed-tramp--decode-context-name (nth 0 (split-string host "%"))) - 'utf-8))) - "")) - -(defun kubed-tramp--context (vec) - "Extract the context name from a kubernetes host name in VEC." - (or (when-let ((host (and vec (tramp-file-name-host vec)))) - (nth 0 (split-string host "%"))) - "")) - -(defun kubed-tramp--namespace (vec) - "Extract the namespace from a kubernetes host name in VEC." - (or (when-let ((host (and vec (tramp-file-name-host vec)))) - (nth 1 (split-string host "%"))) - "")) - -(defun kubed-tramp--pod (vec) - "Extract the pod name from a kubernetes host name in VEC." - (or (when-let ((host (and vec (tramp-file-name-host vec)))) - (nth 2 (split-string host "%"))) - "")) - -(defun kubed-tramp--container (vec) - "Extract the container name from a kubernetes host name in VEC." - (or (when-let ((host (and vec (tramp-file-name-host vec)))) - (nth 3 (split-string host "%"))) - "")) - -;;;###autoload -(defun kubed-tramp-context (file-name) - "Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME." - ;; TODO: Dispatch based on method version. The following is intended - ;; for v2, although it also works for v1 in most cases. - (decode-coding-string - (kubed-tramp--decode-context-name - (nth 0 (split-string - (tramp-file-name-host (tramp-dissect-file-name file-name)) - "%"))) - 'utf-8)) - -;;;###autoload -(defun kubed-tramp-namespace (file-name) - "Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME." - (nth 1 (split-string - (tramp-file-name-host (tramp-dissect-file-name file-name)) "%"))) - -;;;###autoload -(defun kubed-tramp-assert-support () - "Check if Kubed Tramp support is available, throw `user-error' if not." - (unless (assoc kubed-tramp-method tramp-methods) - (user-error "Kubed Tramp support requires Tramp version 2.7 or later"))) - -;;;###autoload -(defun kubed-tramp-enable () - "Enable Kubed integration with Tramp." - (when (boundp 'tramp-extra-expand-args) ; Tramp 2.7+ - - (let ((params `((tramp-login-program ,kubed-kubectl-program) - (tramp-login-args (("exec") - ("--context" "%x") - ("--namespace" "%y") - ("-c" "%a") - ("%h") - ("-it") - ("--") - ("%l"))) - (tramp-direct-async (,tramp-default-remote-shell "-c")) - (tramp-remote-shell ,tramp-default-remote-shell) - (tramp-remote-shell-login ("-l")) - (tramp-remote-shell-args ("-i" "-c"))))) - - ;; Old version. - (setf (alist-get "kubedv1" tramp-methods nil nil #'string=) params) - - (connection-local-set-profile-variables - 'kubed-tramp-connection-local-default-profile - '((tramp-extra-expand-args - ?a (kubed-tramp--container (car tramp-current-connection)) - ?h (kubed-tramp--pod (car tramp-current-connection)) - ?x (kubed-tramp--context (car tramp-current-connection)) - ?y (kubed-tramp--namespace (car tramp-current-connection))))) - - (connection-local-set-profiles - '(:application tramp :protocol "kubedv1") - 'kubed-tramp-connection-local-default-profile) - - ;; New version. - (setf (alist-get kubed-tramp-method tramp-methods nil nil #'string=) params) - - (connection-local-set-profile-variables - 'kubed-tramp-v2-connection-local-default-profile - '((tramp-extra-expand-args - ?a (kubed-tramp--container (car tramp-current-connection)) - ?h (kubed-tramp--pod (car tramp-current-connection)) - ?x (kubed-tramp--v2-context (car tramp-current-connection)) - ?y (kubed-tramp--namespace (car tramp-current-connection))))) - - (connection-local-set-profiles - `(:application tramp :protocol ,kubed-tramp-method) - 'kubed-tramp-v2-connection-local-default-profile)))) - -;;;###autoload (with-eval-after-load 'tramp (kubed-tramp-enable)) - -(provide 'kubed-tramp) -;;; kubed-tramp.el ends here diff --git a/elpa/kubed-0.5.0/kubed-transient.el b/elpa/kubed-0.5.0/kubed-transient.el deleted file mode 100644 index faf861ca..00000000 --- a/elpa/kubed-0.5.0/kubed-transient.el +++ /dev/null @@ -1,588 +0,0 @@ -;;; kubed-transient.el --- Kubernetes transient menus -*- lexical-binding: t; -*- - -;; Copyright (C) 2024-2025 Free Software Foundation, Inc. - -;; Author: Eshel Yaron -;; Keywords: tools - -;;; Commentary: - -;; This library extends Kubed with transient menus for various -;; Kubernetes operations. - -;;; Code: - -(require 'kubed) -(require 'transient) - -(defun kubed-transient-read-date (prompt default _history) - "Prompt with PROMPT for a date, defaulting to DEFAULT. - -Return an RFC3339 string representation of the selected date." - (require 'org) - (when (fboundp 'org-read-date) - (format-time-string "%Y-%m-%dT%H:%M:%S%:z" - (org-read-date 'with-time t nil prompt default)))) - -(defun kubed-transient-read-context (prompt _initial-input _history) - "Prompt with PROMPT for Kubernetes context." - (kubed-read-context prompt (kubed-local-context))) - -(defun kubed-transient-read-namespace (prompt _initial-input _history) - "Prompt with PROMPT for Kubernetes namespace." - (let ((context (or (seq-some (lambda (s) - (and (cl-typep s 'transient-infix) - (equal (oref s argument) "--context=") - (oref s value))) - transient--suffixes) - (kubed-local-context)))) - (kubed-read-namespace prompt (kubed--namespace context) nil context))) - -(defun kubed-transient-read-ingressclass (prompt _initial-input _history) - "Prompt with PROMPT for Kubernetes ingress class." - (kubed-read-ingressclass prompt)) - -(defun kubed-transient-read-service-and-port (prompt _initial-input _history) - "Prompt with PROMPT for Kubernetes service and port number." - (let ((service (kubed-read-service prompt))) - (concat service ":" (number-to-string (read-number "Port number: "))))) - -(defun kubed-transient-read-resource-definition-file-name - (_prompt _initial-input _history) - "Read and return Kubernetes resource definition file name." - (kubed-read-resource-definition-file-name)) - -;;;###autoload (autoload 'kubed-transient "kubed-transient" nil t) -(transient-define-prefix kubed-transient () - "Perform Kubernetes operation." - ["Kubernetes" - [ :pad-keys t - ("RET" "Display" kubed-transient-display) - ("+" "Create" kubed-transient-create) - ("*" "Apply" kubed-transient-apply) - ("D" "Delete" kubed-transient-delete)] - [("e" "Edit" kubed-transient-edit) - ("r" "Run" kubed-transient-run) - ("a" "Attach" kubed-transient-attach) - ("X" "Exec" kubed-transient-exec)] - [("l" "Logs" kubed-transient-logs) - ("d" "Diff" kubed-transient-diff) - ("P" "Patch" kubed-transient-patch) - ("R" "Rollout" kubed-transient-rollout)] - [("$" "Scale" kubed-transient-scale-deployment) - (":" "Proxy" kubed-transient-proxy) - ("E" "Explain" kubed-explain) - ("!" "Command line" kubed-kubectl-command)]]) - -(defmacro kubed-transient-logs-for-resource (resource &optional plural) - "Define transient menu for showing logs for Kubernetes RESOURCE. - -Optional argument PLURAL is the plural form of RESOURCE. If nil, it -defaults to \"RESOURCEs\"." - (let ((name (intern (concat "kubed-transient-logs-for-" resource)))) - `(transient-define-prefix ,name (&optional value) - ,(format "Show logs for a Kubernetes %s." resource) - [,(format "Kubernetes Logs for %s\n" (capitalize resource)) - ["Actions" - ("l" "Show Logs" ,(intern (concat "kubed-logs-for-" resource))) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-b" "Limit bytes" "--limit-bytes=" - :prompt "Bytes limit: " :reader transient-read-number-N+) - ("-t" "Limit lines" "--tail=" - :prompt "Lines limit: " :reader transient-read-number-N+) - ("-S" "Since time" "--since-time=" - :prompt "Since time: " :reader kubed-transient-read-date)] - ["Switches" - ("-A" "All containers" "--all-containers") - ("-f" "Stream logs" "--follow") - ("-P" "Add pod and container" "--prefix") - ("-T" "Add timestamps" "--timestamps")]] - (interactive - (list (kubed-transient-args 'kubed-transient-logs))) - (transient-setup ',name nil nil - :value value - :scope '("logs" ,(concat (or plural - (concat resource "s")) - "/")))))) - -;;;###autoload (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t) -(kubed-transient-logs-for-resource "pod") - -;;;###autoload (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t) -(kubed-transient-logs-for-resource "deployment") - -;;;###autoload (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t) -(kubed-transient-logs-for-resource "service") - -;;;###autoload (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t) -(kubed-transient-logs-for-resource "job") - -;;;###autoload (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t) -(kubed-transient-logs-for-resource "replicaset") - -;;;###autoload (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t) -(kubed-transient-logs-for-resource "daemonset") - -;;;###autoload (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t) -(kubed-transient-logs-for-resource "statefulset") - -;;;###autoload (autoload 'kubed-transient-logs "kubed-transient" nil t) -(transient-define-prefix kubed-transient-logs () - "Show logs for containers running in Kubernetes." - ["Kubernetes Logs\n" - ["Kinds" - ("p" "Pod" kubed-transient-logs-for-pod) - ("d" "Deployment" kubed-transient-logs-for-deployment) - ("j" "Job" kubed-transient-logs-for-job) - ("s" "Service" kubed-transient-logs-for-service) - ("l" "Any type" kubed-logs) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-b" "Limit bytes" "--limit-bytes=" - :prompt "Bytes limit: " :reader transient-read-number-N+) - ("-t" "Limit lines" "--tail=" - :prompt "Lines limit: " :reader transient-read-number-N+) - ("-S" "Since time" "--since-time=" - :prompt "Since time: " :reader kubed-transient-read-date)] - ["Switches" - ("-A" "All containers" "--all-containers") - ("-f" "Stream logs" "--follow") - ("-P" "Add pod and container" "--prefix") - ("-T" "Add timestamps" "--timestamps")]] - (interactive) - (transient-setup 'kubed-transient-logs nil nil - :scope '("logs"))) - -;;;###autoload (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t) -(transient-define-prefix kubed-transient-scale-deployment () - "Scale Kubernetes deployments." - ["Kubernetes Scale Deployment\n" - ["Action" - ("$" "Scale" kubed-scale-deployment) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-r" "Replicas" "--replicas=" - :prompt "Number of replicas: " :reader transient-read-number-N+)]] - (interactive) - (transient-setup 'kubed-transient-scale-deployment nil nil - :scope '("scale" "deployment"))) - -;;;###autoload (autoload 'kubed-transient-proxy "kubed-transient" nil t) -(transient-define-prefix kubed-transient-proxy () - "Create a proxy between localhost and the Kubernetes API server." - ["Kubernetes Proxy\n" - ["Action" - (":" "Start proxy" kubed-proxy) - ("|" "Stop proxy" kubed-stop-proxy) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-a" "Address" "--address=" - :prompt "Local proxy address: ") - ("-p" "Port" "--port=" - :prompt "Local proxy port: " :reader transient-read-number-N0) - ("-w" "WWW directory" "--www=" - :prompt "Local WWW directory: " :reader transient-read-existing-directory) - ("-P" "WWW prefix" "--www-prefix=" - :prompt "WWW prefix: ") - ("-A" "API prefix" "--api-prefix=" - :prompt "API prefix: ")]] - (interactive) - (transient-setup 'kubed-transient-proxy nil nil - :scope '("proxy"))) - -;;;###autoload (autoload 'kubed-transient-rollout "kubed-transient" nil t) -(transient-define-prefix kubed-transient-rollout () - "Manage Kubernetes deployments." - ["Kubernetes Rollout\n" - ["Actions" - ("W" "Watch" kubed-watch-deployment-status) - ("R" "Restart" kubed-restart-deployment) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-rollout nil nil - :scope '("rollout"))) - -;;;###autoload (autoload 'kubed-transient-attach "kubed-transient" nil t) -(transient-define-prefix kubed-transient-attach () - "Attach to running process in container in Kubernetes pod." - ["Kubernetes Attach\n" - ["Actions" - ("a" "Attach" kubed-attach) - ("!" "Command line" kubed-kubectl-command)] - ["Switches" - ("-i" "Open stdin" "--stdin") - ("-t" "Allocate TTY" "--tty")] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-attach nil nil - :value '("--stdin" "--tty") - :scope '("attach"))) - -;;;###autoload (autoload 'kubed-transient-diff "kubed-transient" nil t) -(transient-define-prefix kubed-transient-diff () - "Display difference between Kubernetes resource definition and current state." - ["Kubernetes Diff\n" - ["Actions" - ("d" "Diff" kubed-diff) - ("!" "Command line" kubed-kubectl-command)] - ["Switches" - ("-M" "Include managed fields" "--show-managed-fields")] - ["Options" - ("-f" "Definition file" "--filename=" - :reader kubed-transient-read-resource-definition-file-name) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-diff nil nil - :scope '("diff"))) - -;;;###autoload (autoload 'kubed-transient-exec "kubed-transient" nil t) -(transient-define-prefix kubed-transient-exec () - "Execute command in Kubernetes pod." - ["Kubernetes Exec\n" - ["Actions" - ("X" "Execute" kubed-exec) - ("!" "Command line" kubed-kubectl-command)] - ["Switches" - ("-i" "Open stdin" "--stdin") - ("-t" "Allocate TTY" "--tty")] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("--" "Command" "-- =" - :prompt "Command: ")]] - (interactive) - (transient-setup 'kubed-transient-exec nil nil - :value '("--stdin" "--tty") - :scope '("exec"))) - -;;;###autoload (autoload 'kubed-transient-run "kubed-transient" nil t) -(transient-define-prefix kubed-transient-run () - "Run container image in a Kubernetes pod." - ["Kubernetes Run\n" - ["Actions" - ("r" "Run" kubed-run) - ("!" "Command line" kubed-kubectl-command)] - ["Switches" - ("-A" "Attach" "--attach") - ("-i" "Open stdin" "--stdin") - ("-t" "Allocate TTY" "--tty") - ("-R" "Remove after exit" "--rm") - ("-c" "Override container command" "--command")] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-I" "Image" "--image=" - :prompt "Image to deploy: ") - ("-p" "Port" "--port=" - :prompt "Port to expose: " :reader transient-read-number-N+) - ("-E" "Env vars" "--env=" - :prompt "Set environment VAR=VAL: " - :multi-value repeat) - ("--" "Arguments" "-- =" - :prompt "Arguments for container command: ")]] - (interactive) - (transient-setup 'kubed-transient-run nil nil - :scope '("run"))) - -;;;###autoload (autoload 'kubed-transient-apply "kubed-transient" nil t) -(transient-define-prefix kubed-transient-apply () - "Apply configuration to Kubernetes resource." - ["Kubernetes Apply\n" - ["Actions" - ("*" "Apply" kubed-apply) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-f" "Definition file" "--filename=" - :reader kubed-transient-read-resource-definition-file-name) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-apply nil nil - :scope '("apply"))) - -;;;###autoload (autoload 'kubed-transient-patch "kubed-transient" nil t) -(transient-define-prefix kubed-transient-patch () - "Apply patch to Kubernetes resource." - ["Kubernetes Patch\n" - ["Actions" - ("P" "Patch" kubed-patch) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-t" "Patch type" "--type=" - :prompt "Patch type: " - :choices ("strategic" "merge" "json"))]] - (interactive) - (transient-setup 'kubed-transient-patch nil nil - :scope '("patch"))) - -;;;###autoload (autoload 'kubed-transient-create "kubed-transient" nil t) -(transient-define-prefix kubed-transient-create () - "Create Kubernetes resource." - ["Kubernetes Create\n" - ["Kinds" - ("p" "Pod" kubed-create-pod) - ("d" "Deployment" kubed-transient-create-deployment) - ("j" "Job" kubed-transient-create-job) - ("c" "CronJob" kubed-transient-create-cronjob) - ("s" "Service" kubed-create-service)] - ["More" - :pad-keys t - ("S" "Secret" kubed-create-secret) - ("N" "Namespace" kubed-create-namespace) - ("i" "Ingress" kubed-transient-create-ingress) - ("+" "Any type" kubed-create) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-f" "Definition file" "--filename=" - :reader kubed-transient-read-resource-definition-file-name) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-create nil nil - :scope '("create"))) - -;;;###autoload (autoload 'kubed-transient-display "kubed-transient" nil t) -(transient-define-prefix kubed-transient-display () - "Display Kubernetes resource." - ["Kubernetes Display\n" - ["Kinds" - ("p" "Pod" kubed-display-pod) - ("d" "Deployment" kubed-display-deployment) - ("j" "Job" kubed-display-job) - ("c" "CronJob" kubed-display-cronjob) - ("s" "Service" kubed-display-service)] - ["More" - :pad-keys t - ("S" "Secret" kubed-display-secret) - ("N" "Namespace" kubed-display-namespace) - ("i" "Ingress" kubed-display-ingress) - ("RET" "Any type" kubed-display-resource) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-display nil nil - :scope '("get"))) - -;;;###autoload (autoload 'kubed-transient-edit "kubed-transient" nil t) -(transient-define-prefix kubed-transient-edit () - "Edit Kubernetes resource." - ["Kubernetes Edit\n" - ["Kinds" - ("p" "Pod" kubed-edit-pod) - ("d" "Deployment" kubed-edit-deployment) - ("j" "Job" kubed-edit-job) - ("c" "CronJob" kubed-edit-cronjob) - ("s" "Service" kubed-edit-service)] - ["More" - :pad-keys t - ("S" "Secret" kubed-edit-secret) - ("N" "Namespace" kubed-edit-namespace) - ("i" "Ingress" kubed-edit-ingress) - ("RET" "Any type" kubed-edit-resource) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-edit nil nil - :scope '("edit"))) - -;;;###autoload (autoload 'kubed-transient-delete "kubed-transient" nil t) -(transient-define-prefix kubed-transient-delete () - "Delete Kubernetes resource." - ["Kubernetes Delete\n" - ["Kinds" - ("p" "Pod" kubed-delete-pods) - ("d" "Deployment" kubed-delete-deployments) - ("j" "Job" kubed-delete-jobs) - ("c" "CronJob" kubed-delete-cronjobs) - ("s" "Service" kubed-delete-services)] - ["More" - :pad-keys t - ("S" "Secret" kubed-delete-secrets) - ("N" "Namespace" kubed-delete-namespaces) - ("i" "Ingress" kubed-delete-ingresses) - ("D" "Any type" kubed-delete-resources) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context)]] - (interactive) - (transient-setup 'kubed-transient-delete nil nil - :scope '("delete"))) - -;;;###autoload (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t) -(transient-define-prefix kubed-transient-create-cronjob () - "Create Kubernetes cronjob." - ["Kubernetes Create CronJob\n" - ["Actions" - ("+" "Create" kubed-create-cronjob) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-I" "Image" "--image=" - :prompt "Image to run: ") - ("-S" "Schedule" "--schedule=" - :prompt "Cron schedule: ") - ("--" "Command" "-- =" - :prompt "Command: ")]] - (interactive) - (transient-setup 'kubed-transient-create-cronjob nil nil - :scope '("create" "cronjob"))) - -;;;###autoload (autoload 'kubed-transient-create-ingress "kubed-transient" nil t) -(transient-define-prefix kubed-transient-create-ingress () - "Create Kubernetes ingress." - ["Kubernetes Create Ingress\n" - ["Actions" - ("+" "Create" kubed-create-ingress) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-c" "Class" "--class=" - :prompt "Class" :reader kubed-transient-read-ingressclass) - ("-d" "Default backend service" "--default-backend=" - :prompt "Default backend service" - :reader kubed-transient-read-service-and-port) - ("-a" "Annotation" "--annotation=" - :prompt "Ingress annotations: " - :multi-value repeat) - ("-r" "Rule" "--rule=" - :prompt "Ingress rule: ")]] - (interactive) - (transient-setup 'kubed-transient-create-ingress nil nil - :scope '("create" "ingress"))) - -;;;###autoload (autoload 'kubed-transient-create-deployment "kubed-transient" nil t) -(transient-define-prefix kubed-transient-create-deployment () - "Create Kubernetes deployment." - ["Kubernetes Create Deployment\n" - ["Actions" - ("+" "Create" kubed-create-deployment) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-r" "Replicas" "--replicas=" - :prompt "Number of replicas: " :reader transient-read-number-N+) - ("-I" "Image" "--image=" - :prompt "Images to deploy: " - :multi-value repeat) - ("-p" "Port" "--port=" - :prompt "Port to expose: " :reader transient-read-number-N+) - ("--" "Command" "-- =" - :prompt "Command: ")]] - (interactive) - (transient-setup 'kubed-transient-create-deployment nil nil - :scope '("create" "deployment"))) - -;;;###autoload (autoload 'kubed-transient-create-job "kubed-transient" nil t) -(transient-define-prefix kubed-transient-create-job () - "Create Kubernetes job." - ["Kubernetes Create Job\n" - ["Actions" - ("+" "Create" kubed-create-job) - ("c" "Create from cronjob" kubed-create-job-from-cronjob) - ("!" "Command line" kubed-kubectl-command)] - ["Options" - ("-n" "Namespace" "--namespace=" - :prompt "Namespace" :reader kubed-transient-read-namespace) - ("-C" "Context" "--context=" - :prompt "Context" :reader kubed-transient-read-context) - ("-I" "Image" "--image=" - :prompt "Image to run: ") - ("--" "Command" "-- =" - :prompt "Command: ")]] - (interactive) - (transient-setup 'kubed-transient-create-job nil nil - :scope '("create" "job"))) - -;;;###autoload (autoload 'kubed-list-transient "kubed-transient" nil t) -(transient-define-prefix kubed-list-transient () - "Help for Kubernetes resource list buffers." - ;; TODO: Add a type-specific group with `:setup-children'. - ["Kubernetes Resources:" - ["Select" - :pad-keys t - ("RET" "Select" kubed-list-select-resource) - ("C-o" "Display" kubed-list-display-resource :transient t) - ("e" "Edit" kubed-list-edit :transient t) - ("w" "Copy name" kubed-list-copy-as-kill :transient t) - ("!" "Command line" kubed-list-kubectl-command :transient t)] - ["Delete" - ("D" "Delete" kubed-list-delete :transient t) - ("d" "Mark" kubed-list-mark-for-deletion :transient t) - ("u" "Unmark" kubed-list-unmark :transient t) - ("x" "Delete marked" kubed-list-delete-marked :transient t) - ("+" "Create" kubed-list-create :transient t)] - ["Table" - ("|" "Fit column" kubed-list-fit-column-width-to-content :transient t) - ("}" "Widen column" tabulated-list-widen-current-column :transient t) - ("{" "Narrow column" tabulated-list-narrow-current-column :transient t) - ("S" "Sort" tabulated-list-sort :transient t) - ("/" "Filter" kubed-list-set-filter :transient t)] - ["Movement" - :pad-keys t - ("n" "Next line" next-line :transient t) - ("p" "Previous line" previous-line :transient t) - ("TAB" "Next column" kubed-list-next-column :transient t) - ("S-TAB" "Previous column" kubed-list-previous-column :transient t) - ("g" "Update" kubed-list-update :transient t)]] - ["Type Specific" - :class transient-columns - :setup-children - (lambda (_) - (transient-parse-suffixes 'kubed-list-transient - kubed-list-transient-extra-suffixes))]) - -(provide 'kubed-transient) -;;; kubed-transient.el ends here diff --git a/elpa/kubed-0.5.0/kubed.el b/elpa/kubed-0.5.0/kubed.el deleted file mode 100644 index f28a5e3d..00000000 --- a/elpa/kubed-0.5.0/kubed.el +++ /dev/null @@ -1,3582 +0,0 @@ -;;; kubed.el --- Kubernetes, Emacs, done! -*- lexical-binding: t; -*- - -;; Copyright (C) 2024-2025 Free Software Foundation, Inc. - -;; Author: Eshel Yaron -;; Maintainer: Eshel Yaron <~eshel/kubed-devel@lists.sr.ht> -;; Keywords: tools kubernetes containers -;; URL: https://eshelyaron.com/kubed.html -;; Package-Version: 0.5.0 -;; Package-Requires: ((emacs "29.1")) - -;;; Commentary: - -;; This library defines commands for interacting with Kubernetes -;; resources, such as Kubernetes pods, services, deployments, and more. -;; -;; Use `kubed-display-pod' to display a Kubernetes pod, -;; `kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and -;; `kubed-list-pods' to see a menu of all pods. You can create new pods -;; from YAML or JSON files with `kubed-create-pod'. -;; -;; Similar commands are defined for other types of resources as well. -;; -;; This library interacts with Kubernetes via `kubectl', and uses the -;; current `kubectl' context and namespace by default. To change your -;; current context or namespace, use commands `kubed-use-context' and -;; `kubed-set-namespace' respectively; you can also interact with -;; resources in other namespaces without changing your default -;; namespace, for example you can call `kubed-list-pods' with a prefix -;; argument to choose another namespace for listing pods. The prefix -;; keymap `kubed-prefix-map' gives you quick access to these and other -;; useful commands, you may want to bind it globally to a convenient key -;; with `keymap-global-set': -;; -;; (keymap-global-set "C-c k" 'kubed-prefix-map) -;; -;; In addition, the command `kubed-transient' lets you explore various -;; Kubernetes operations with a transient menu interface. You may also -;; want to enable `kubed-menu-bar-mode', which add a "Kubernetes" menu -;; to your menu-bar with many useful entries. -;; -;; If you want to work with more or different types of Kubernetes -;; resources, use the macro `kubed-define-resource'. This macro defines -;; some common functions and commands that'll get you started with ease. -;; -;; For more information, see the Kubed manual at (info "(kubed)Top"), or -;; online at https://eshelyaron.com/kubed.html - -;;; Code: - -(require 'kubed-common) - -(defgroup kubed nil - "Kubernetes interface." - :group 'tools) - -(defcustom kubed-default-context-and-namespace nil - "Default `kubectl' context and Kubernetes namespace. - -This is either a cons cell (CONTEXT . NAMESPACE), or nil. If nil, Kubed -initializes this option to a non-nil value next time Kubed consults it." - :type '(choice (const :tag "Initialize from `kubectl' on first use" nil) - (cons :tag "Context and namespace" - (string :tag "Context") - (string :tag "Namespace")))) - -(defcustom kubed-yaml-setup-hook '(yaml-ts-mode view-mode) - "List of functions to call in Kubernetes resource description YAML buffers. - -The first function in the list should normally be the major mode to use, -by default it is `yaml-ts-mode'." - :type 'hook) - -(defcustom kubed-logs-setup-hook '(view-mode) - "List of functions to call when setting up Kubernetes pod logs buffers." - :type 'hook) - -(defcustom kubed-name-column '("Name" 48 t) - "Specification of resource name column in Kubernetes resource list buffers." - :type '(list string natnum boolean)) - -(defvar kubed--data nil) - -(defun kubed--alist (type context namespace) - "Return information about resources in CONTEXT of type TYPE in NAMESPACE." - (alist-get namespace - (alist-get type - (alist-get context - kubed--data nil nil #'string=) - nil nil #'string=) - nil nil #'equal)) - -(gv-define-setter kubed--alist (value type context namespace) - `(setf (alist-get ,namespace - (alist-get ,type - (alist-get ,context - kubed--data nil nil #'string=) - nil nil #'string=) - nil nil #'equal) - ,value)) - -(defvar kubed--columns nil) - -(defun kubed-update (type context &optional namespace) - "Update list of resources of type TYPE in CONTEXT and NAMESPACE." - (when (process-live-p (alist-get 'process (kubed--alist type context namespace))) - (user-error "Update in progress")) - (let* ((out (get-buffer-create (format " *kubed-get-%s*" type))) - (err (get-buffer-create (format " *kubed-get-%s-stderr*" type))) - (columns (alist-get type kubed--columns nil nil #'string=))) - (with-current-buffer out (erase-buffer)) - (setf (alist-get 'process (kubed--alist type context namespace)) - (make-process - :name (format "*kubed-get-%s*" type) - :buffer out - :stderr err - :command (append - (list kubed-kubectl-program "get" type - "--context" context - (format "--output=custom-columns=%s" - (mapconcat #'car columns ","))) - (when namespace (list "--namespace" namespace))) - :sentinel - (lambda (_proc status) - (cond - ((string= status "finished\n") - (let (new offsets eol) - (with-current-buffer out - (goto-char (point-min)) - (setq eol (pos-eol)) - (while (re-search-forward "[^ ]+" eol t) - (push (1- (match-beginning 0)) offsets)) - (setq offsets (nreverse offsets)) - (forward-char 1) - (while (not (eobp)) - (let ((cols nil) - (beg (car offsets)) - (ends (append (cdr offsets) - (list (- (pos-eol) (point)))))) - (dolist (column columns) - (let ((str (string-trim (buffer-substring - (+ (point) beg) - (+ (point) (car ends)))))) - (push (if-let ((f (cdr column))) (funcall f str) str) - cols) - (setq beg (pop ends)))) - (push (nreverse cols) new)) - (forward-line 1))) - (setf (kubed--alist type context namespace) - (list (cons 'resources - (mapcar (lambda (c) (list (car c) (apply #'vector c))) - new)))) - (let ((bufs nil)) - (dolist (buf (buffer-list)) - (and (equal (buffer-local-value 'kubed-list-type buf) type) - (equal (buffer-local-value 'kubed-list-context buf) context) - (equal (buffer-local-value 'kubed-list-namespace buf) namespace) - (with-current-buffer buf - (when (derived-mode-p 'kubed-list-mode) - (revert-buffer) - (when-let ((win (get-buffer-window))) - (set-window-point win (point)) - (push buf bufs)))))) - (walk-windows - (lambda (win) - (let ((buf (window-buffer win))) - (when (memq buf bufs) - (set-window-point - win (with-current-buffer buf (point)))))))) - (message (format "Updated Kubernetes %S." type)))) - ((string= status "exited abnormally with code 1\n") - (with-current-buffer err - (goto-char (point-max)) - (insert "\n" status)) - (display-buffer err)))))))) - -(defvar-local kubed-display-resource-info nil - "Information about Kubernetes resource that current buffer displays. - -The value is a list (TYPE NAME CONTEXT NAMESPACE), where TYPE is the -type of the resource, NAME is the name of the resource, CONTEXT is the -`kubectl' context to use for accessing the resource, and NAMESPACE is -the namespace of the resource, or nil if TYPE is not namespaced.") - -(put 'kubed-display-resource-info 'permanent-local t) - -(defun kubed-display-resource-revert (&optional _ _) - "Clear and populate current Kubernetes resource buffer." - (seq-let (type name context namespace) - kubed-display-resource-info - (let ((inhibit-read-only t) - (target (current-buffer))) - (buffer-disable-undo) - (with-temp-buffer - (unless (zerop - (apply - #'call-process - kubed-kubectl-program nil t nil "get" - type "--output=yaml" name - (append (when namespace (list "-n" namespace)) - (when context (list "--context" context))))) - (error "Failed to display Kubernetes resource `%s'" name)) - (let ((source (current-buffer))) - (with-current-buffer target - (replace-buffer-contents source) - (set-buffer-modified-p nil) - (buffer-enable-undo))))))) - -(defun kubed-display-resource-in-buffer - (buffer type resource &optional context namespace) - "Display Kubernetes RESOURCE of type TYPE in BUFFER." - (let ((info (list type resource context namespace))) - (with-current-buffer (get-buffer-create buffer) - (setq-local kubed-display-resource-info info) - (kubed-display-resource-revert) - (goto-char (point-min)) - (run-hooks 'kubed-yaml-setup-hook) - (kubed-display-resource-mode) - (current-buffer)))) - -(defun kubed-display-resource-short-description - (type resource context namespace) - "Return short string to use as a label for RESOURCE of type TYPE." - (concat type "/" resource - (when namespace (concat "@" namespace)) - (when context (concat "[" context "]")))) - -(defun kubed-namespaced-p (type &optional context) - "Return non-nil if TYPE is a namespaced resource type in context CONTEXT." - (member type (kubed-api-resources context t))) - -(defun kubed--namespace (context &optional prompt-p) - "Return Kubernetes namespace for CONTEXT. - -Non-nil optional argument PROMPT-P says to prompt for a namespace." - (let ((ns (if (equal context (kubed-local-context)) - (kubed-local-namespace) - (kubed-current-namespace context)))) - ;; If CONTEXT is another context that has no configured namespace, - ;; then NS is nil and we must prompt. - (unless ns (setq prompt-p t)) - (if prompt-p - (kubed-read-namespace "Namespace" ns nil context) - ns))) - -;;;###autoload -(defun kubed-display-resource - (type resource context &optional namespace) - "Display Kubernetes RESOURCE of type TYPE in CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCE. With a prefix argument \ -\\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \ -\\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well." - (interactive - (let ((type nil) (context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-display)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless type - (setq type (kubed-read-resource-type "Type of resource to display" - nil context))) - (when (and (null namespace) (kubed-namespaced-p type context)) - (setq namespace (kubed--namespace context current-prefix-arg))) - (list type (kubed-read-resource-name type "Display" nil nil - context namespace) - context namespace))) - (display-buffer - (kubed-display-resource-in-buffer - (concat "*Kubed " - (kubed-display-resource-short-description - type resource context namespace) - "*") - type resource context namespace))) - -(declare-function bookmark-prop-get "bookmark") -(declare-function bookmark-get-front-context-string "bookmark") -(declare-function bookmark-get-rear-context-string "bookmark") -(declare-function bookmark-make-record-default "bookmark") - -;;;###autoload -(defun kubed-display-resource-handle-bookmark (bookmark) - "Display Kubernetes resource according to BOOKMARK." - (require 'bookmark) - (seq-let (type name context namespace) - (bookmark-prop-get bookmark 'resource) - (set-buffer - (kubed-display-resource-in-buffer - (concat "*Kubed " - (kubed-display-resource-short-description - type name context namespace) - "*") - type name context namespace)) - (when-let ((str (bookmark-get-front-context-string bookmark)) - ((search-forward str (point-max) t))) - (goto-char (match-beginning 0))) - (when-let ((str (bookmark-get-rear-context-string bookmark)) - ((search-backward str (point-min) t))) - (goto-char (match-end 0))))) - -(put 'kubed-display-resource-handle-bookmark 'bookmark-handler-type "KubedResource") - -(defun kubed-display-resource-make-bookmark () - "Return bookmark pointing to currently displayed Kubernetes resource." - (require 'bookmark) - (seq-let (type name context namespace) kubed-display-resource-info - (cons - (kubed-display-resource-short-description type name context namespace) - (append - (list - (cons 'handler #'kubed-display-resource-handle-bookmark) - (cons 'resource kubed-display-resource-info)) - (bookmark-make-record-default t))))) - -(defun kubed-display-resource-jump-to-list () - "Jump to line in resources list that corresponds to the displayed resource." - (interactive) - (seq-let (type name context namespace) kubed-display-resource-info - (apply (intern (concat "kubed-list-" type)) context - (when namespace (list namespace))) - (kubed-list-go-to-line name))) - -(defun kubed-display-resource-diff () - "Show diff of current buffer with current state of the displayed resource." - (interactive) - (kubed-diff (current-buffer) nil (nth 2 kubed-display-resource-info))) - -(defun kubed-display-resource-replace () - "Replace displayed Kubernetes resource with current buffer contents." - (interactive) - (let (choice) - (while (= ?d (setq choice - (car (read-multiple-choice - "Replace resource with changes in current buffer?" - '((?y "yes") (?n "no") (?d "diff")))))) - (kubed-display-resource-diff)) - (when (= ?y choice) - (let ((err-buf (get-buffer-create " *kubed-replace*"))) - (with-current-buffer err-buf (erase-buffer)) - (unless (zerop (call-process-region nil nil kubed-kubectl-program - nil err-buf nil "replace" "-f" "-")) - (display-buffer err-buf) - (user-error "`kubectl replace' failed!"))) - (message "Replaced Kubernetes resource with changes in current buffer.") - (revert-buffer)))) - -(defun kubed-display-resource-p (_symbol buffer) - "Return non-nil if `kubed-display-resource-mode' is enabled in BUFFER. - -The first argument, SYMBOL, is ignored. You can use this function as -the `completion-predicate' property of commands that you define that -should only be available in buffers that display Kubernetes resources." - (buffer-local-value 'kubed-display-resource-mode buffer)) - -(dolist (cmd '(kubed-display-resource-jump-to-list - kubed-display-resource-diff - kubed-display-resource-replace)) - (put cmd 'completion-predicate #'kubed-display-resource-p)) - -(defvar-keymap kubed-display-resource-mode-map - :doc "Keymap buffers that display Kubernetes resource." - "C-c C-j" #'kubed-display-resource-jump-to-list - "C-c C-=" #'kubed-display-resource-diff - "C-c C-c" #'kubed-display-resource-replace) - -(define-minor-mode kubed-display-resource-mode - "Minor mode for buffers that display a Kubernetes resource." - :interactive nil - :lighter " Kubed" - (when kubed-display-resource-mode - (setq-local - revert-buffer-function #'kubed-display-resource-revert - bookmark-make-record-function #'kubed-display-resource-make-bookmark))) - -(defun kubed-list-filter-lt-operator (v s) - "Return non-nil if S is less than V as a number or as a string." - (let ((l (string-to-number s)) (r (string-to-number v))) - (if (= l r) (string< s v) (< l r)))) - -(defun kubed-list-filter-gt-operator (v s) - "Return non-nil if S is greater than V as a number or as a string." - (let ((l (string-to-number s)) (r (string-to-number v))) - (if (= l r) (string> s v) (> l r)))) - -(defcustom kubed-list-filter-operator-alist - '((= . string=) - (~ . string-match-p) - (< . kubed-list-filter-lt-operator) - (> . kubed-list-filter-gt-operator)) - "Association list of filter operators and functions that implement them. - -Elements of the list are cons cells (OP . FN), where OP is a symbol that -is used as a filter operator and FN is a function that implements OP. -FN takes two arguments, a string STR and a parameter VAL. FN should -return non-nil if STR and VAL are related according to OP: to determine -if a line in which column COL is STR satisfies the filter (OP COL VAL), -Kubed checks if the form (FN VAL STR) evaluates to non-nil." - :type '(alist :key-type (symbol :tag "Operator") :value-type function)) - -(defun kubed-list-interpret-atomic-filter (atom) - "Return function that implements atomic filter ATOM." - (if (eq (car-safe atom) 'quote) - (let ((p (kubed-list-interpret-atomic-filter (cadr atom)))) - (lambda (x) (not (funcall p x)))) - (let* ((column-number (tabulated-list--column-number (symbol-name (nth 1 atom)))) - (value (nth 2 atom)) - (value (if (stringp value) value (prin1-to-string value))) - (op (alist-get (car atom) kubed-list-filter-operator-alist))) - (unless op (user-error "Unknown filter operator `%S'" (car atom))) - (lambda (x) (funcall op value (aref (cadr x) column-number)))))) - -(defvar-local kubed-list-filter nil "Filter in effect in the current buffer.") - -(defun kubed-list-interpret-filter (&optional filter) - "Return function that implements FILTER. - -If FILTER is omitted or nil, it defaults to `kubed-list-filter'." - (let ((conjunction (or filter kubed-list-filter))) - (if (listp (car conjunction)) - (let ((conjuncts - (mapcar (lambda (disjunction) - (if (listp (car disjunction)) - (let ((disjuncts - (mapcar #'kubed-list-interpret-atomic-filter - disjunction))) - (lambda (entry) - (catch 'keep-it - (dolist (pred disjuncts) - (when (funcall pred entry) - (throw 'keep-it t))) - nil))) - ;; Single atomic disjunct. - (kubed-list-interpret-atomic-filter disjunction))) - (or conjunction kubed-list-filter)))) - (lambda (entry) - (catch 'keep-it - (dolist (pred conjuncts) - (unless (funcall pred entry) - (throw 'keep-it nil))) - t))) - ;; Single atomic conjunct. - (kubed-list-interpret-atomic-filter conjunction)))) - -(defun kubed-list-validate-atomic-filter (atom) - "Return string explaining why ATOM is invalid, or nil if it is valid." - (unless (consp atom) - (throw 'validation-error - (format (substitute-quotes - "Invalid atomic filter `%S', must be a list") - atom))) - (if (eq (car-safe atom) 'quote) - (kubed-list-validate-atomic-filter (cadr atom)) - (unless (length= atom 3) - (throw 'validation-error - (format (substitute-quotes - "Invalid atomic filter `%S', must have three elements") - atom))) - (unless (assq (car atom) kubed-list-filter-operator-alist) - (throw 'validation-error - (format (substitute-quotes - "No operator `%S' in `kubed-list-filter-operator-alist'") - (car atom)))) - (unless (ignore-errors - (tabulated-list--column-number (symbol-name (nth 1 atom)))) - (throw 'validation-error (format (substitute-quotes - "Invalid column name `%S'") - (nth 1 atom)))))) - -(defun kubed-list-validate-filter (filter) - "Return string explaining why FILTER is invalid, or nil if it is valid." - (catch 'validation-error - (if (listp (car-safe filter)) - (dolist (disjunction filter) - (if (and (consp disjunction) (listp (car disjunction))) - (dolist (disjunct disjunction) - (kubed-list-validate-atomic-filter disjunct)) - (kubed-list-validate-atomic-filter disjunction))) - (kubed-list-validate-atomic-filter filter)))) - -(defvar-local kubed-list-filter-history-variable nil - "History list variable to use for filter history in the current buffer.") - -(defvar-local kubed--list-read-filter-target-buffer nil - "Resource list buffer for which this minibuffer is reading a filter.") - -(defvar-local kubed-list-type nil) -(defvar-local kubed-list-context nil) -(defvar-local kubed-list-namespace nil) - -(defvar-local kubed-list-transient-extra-suffixes nil - "List of transient suffixes for the type of resources in current buffer.") - -(defun kubed-list-go-to-line (id) - "Go to beginning of table line with ID." - (let ((pos nil)) - (save-excursion - ;; Wait for refresh to finish, if currently underway. - (while (process-live-p - (alist-get 'process (kubed--alist kubed-list-type - kubed-list-context - kubed-list-namespace))) - (accept-process-output - (alist-get 'process (kubed--alist kubed-list-type - kubed-list-context - kubed-list-namespace)) - 1)) - (goto-char (point-min)) - (while (not (or pos (eobp))) - (if (equal id (tabulated-list-get-id)) - (setq pos (point)) - (forward-line)))) - (goto-char pos))) - -(defun kubed-list-try-read-filter () - "Try to read a resource list filter in the minibuffer. - -Exit the minibuffer if successful, else report the error and move point -to the location of the error. If point is not already at the location -of the error, push a mark before moving point." - (interactive "" minibuffer-mode) - (let* ((prompt-end (minibuffer-prompt-end)) - (contents (minibuffer-contents)) - (error-point nil) (error-message nil) (form nil) (inval nil)) - (with-temp-buffer - (condition-case err - (progn - ;; FIXME: There is a small edge case here that could get - ;; better treatment: when `contents' ends with " ?", it - ;; espaces the terminating closing parenthesis and leads us - ;; to incorrectly report the input as incomplete. - (insert "(" contents ")") - (goto-char (point-min)) - (setq form (read (current-buffer)))) - (error (setq error-point (+ prompt-end (1- (point))) - error-message err)))) - (cond - (error-point - (unless (= (point) error-point) (push-mark)) - (goto-char error-point) - (minibuffer-message (error-message-string error-message))) - ((setq inval (with-current-buffer kubed--list-read-filter-target-buffer - (kubed-list-validate-filter form))) - (minibuffer-message inval)) - (t (exit-minibuffer))))) - -(defvar-keymap kubed-list-read-filter-map - :parent minibuffer-local-map - "TAB" #'completion-at-point - "M-?" #'completion-help-at-point - " " #'kubed-list-try-read-filter) - -(defun kubed-list-read-filter (prompt) - "Prompt with PROMPT for a filter for the current buffer." - (let* ((buf (current-buffer)) - (cols (seq-map #'car tabulated-list-format)) - (vals (let ((tmp nil)) - (dolist (ent (alist-get 'resources - (kubed--alist kubed-list-type - kubed-list-context - kubed-list-namespace))) - (let ((i 0)) - (dolist (col cols) - (push (aref (cadr ent) i) - (alist-get col tmp nil nil #'string=)) - (setq i (1+ i))))) - (mapcar #'delete-dups tmp))) - (filter - (minibuffer-with-setup-hook - (lambda () - (set-syntax-table emacs-lisp-mode-syntax-table) - (setq-local kubed--list-read-filter-target-buffer buf) - (add-hook - 'completion-at-point-functions - (lambda () - (let ((cont (buffer-substring - (minibuffer-prompt-end) (point))) - (bounds (or (bounds-of-thing-at-point 'symbol) - (cons (point) (point))))) - (with-temp-buffer - (set-syntax-table emacs-lisp-mode-syntax-table) - (insert "(" cont) - (when-let ((fn-argi (elisp--fnsym-in-current-sexp)) - (argi (cadr fn-argi))) - (if (= argi 0) - ;; Complete operators. - (list - (car bounds) (cdr bounds) - (mapcar #'car kubed-list-filter-operator-alist)) - (when (car fn-argi) - (cond - ((= argi 1) - ;; Complete column names. - (list (car bounds) (cdr bounds) cols)) - ((= argi 2) - ;; Complete column values. - (when-let ((beg (nth 1 (syntax-ppss))) - ;; Grab preceding symbol. - (col (save-excursion - (goto-char beg) - (forward-char 1) - (forward-sexp 2) - (thing-at-point 'symbol)))) - (list (car bounds) (cdr bounds) - (alist-get col vals - nil nil #'string=))))))))))) - nil t)) - (read-from-minibuffer - (format-prompt prompt "disable") - (mapconcat #'prin1-to-string kubed-list-filter " ") - kubed-list-read-filter-map nil - kubed-list-filter-history-variable "")))) - (car (ignore-errors (read-from-string (format "(%s)" filter)))))) - -(defun kubed-list-set-filter (filter) - "Set the filter of the current buffer to FILTER. - -FILTER determines which resources to keep. FILTER can be an atomic -filter, which is a list (OP COL VAL), where OP is an operator defined in -`kubed-list-filter-operator-alist' (which see), COL is a symbol whose -name is a column name, and VAL is a string or an object whose printed -representation is compared to the value of the column COL according to -OP. For example, the atomic filter (= Name foobar) keeps only resources -whose name is \"foobar\". (= Name \"foobar\") does exactly the same. -To negate an atomic filter, quote it. E.g. use \\='(~ Namespace kube) -to hide all resources in namespaces whose name contains \"kube\". - -FILTER can also be a list of sub-filters (SUB1 SUB2 ...) where each -sub-filter is either an atomic filter or a list of atomic filters. If a -sub-filter is a list of atomic filters, then that sub-filter denotes the -disjunction of those atomic filters. FILTER denotes the conjunction of -the sub-filters. In particular, FILTER nil denotes the empty -conjunction which is always true (keeps all resources). - -More examples: - -- `((= Name foobar) (~ Namespace kube))': keep only resources named - \"foobar\" in namespaces that contain \"kube\". -- `(((= Name foobar) (~ Namespace kube)))': keep resources that are - either named \"foobar\" or in a namespace that contains \"kube\". -- `(((= Name foobar) (~ Namespace kube)) \\='(~ Starttime 2024-07))': - keep only resources that are either named \"foobar\" or in a namespace - that contains \"kube\", and were not started during July 2024. - -Interactively, prompt for FILTER sans the outermost set of parenthesis. -For example, enter \"= Name foobar\" in the minibuffer to specify the -atomic FILTER (= Name foobar). - -See also Info node \"(kubed) List Filter\"." - (interactive (list (kubed-list-read-filter "Set filter")) kubed-list-mode) - (when-let ((validation-error (kubed-list-validate-filter filter))) - (user-error validation-error)) - (setq-local kubed-list-filter filter) - (revert-buffer)) - -(defun kubed-list-mark-for-deletion () - "Mark Kubernetes resource at point for deletion." - (interactive "" kubed-list-mode) - (tabulated-list-put-tag (propertize "D" 'help-echo "Marked for deletion") t)) - -(defun kubed-list-unmark () - "Remove mark from Kubernetes resource at point." - (interactive "" kubed-list-mode) - (tabulated-list-put-tag " " t)) - -(defun kubed-list-previous-column (&optional n) - "Move backward N columns. - -Interactively, N is the numeric value of the prefix argument, defaulting -to 1." - (interactive "p" kubed-list-mode) - (kubed-list-next-column (- n))) - -(defun kubed-list-next-column (&optional n) - "Move forward N columns. - -Interactively, N is the numeric value of the prefix argument, defaulting -to 1." - (interactive "p" kubed-list-mode) - (let ((next (point)) - (times (abs (or n 1))) - (dir-fn (if (< 0 n) - #'next-single-property-change - #'previous-single-property-change))) - (dotimes (_ times) - (setq next (funcall dir-fn next 'tabulated-list-column-name)) - (when (equal (char-after next) ?\n) - ;; At line boundary, go to first/last column of next line. - (setq next (funcall dir-fn next 'tabulated-list-column-name))) - (unless next (user-error "End of table"))) - (goto-char next))) - -(defun kubed-list-copy-as-kill (click) - "Copy name of Kubernetes resource at CLICK into the kill ring." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((ent (tabulated-list-get-entry (mouse-set-point click))) - (new (aref ent 0))) - (progn - (kill-new new) - (message "Copied resource name `%s'" new)) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-context-menu (menu click) - "Extend MENU with common actions on Kubernetes resource at CLICK." - (when (tabulated-list-get-entry (posn-point (event-start click))) - (define-key menu [kubed-list-select-resource] - '(menu-item "Select" kubed-list-select-resource)) - (define-key menu [kubed-list-display-resource] - '(menu-item "Display" kubed-list-display-resource)) - (define-key menu [kubed-list-delete] - '(menu-item "Delete" kubed-list-delete)) - (define-key menu [kubed-list-patch] - '(menu-item "Patch" kubed-list-patch)) - (define-key menu [kubed-list-edit] - '(menu-item "Edit" kubed-list-edit)) - (define-key menu [kubed-list-kubectl-command] - '(menu-item "Execute `kubectl' command" kubed-list-kubectl-command)) - (define-key menu [kubed-list-copy-as-kill] - '(menu-item "Copy name" kubed-list-copy-as-kill))) - menu) - -(defun kubed-list-update (&optional quiet) - "Update list of Kubernetes resources. - -If optional argument QUIET is non-nil, do not emit a message when -starting to update. Display a message when the update is done -regardless of QUIET." - (interactive "" kubed-list-mode) - (kubed-update kubed-list-type kubed-list-context kubed-list-namespace) - (force-mode-line-update) - (unless quiet (minibuffer-message (format "Updating Kubernetes %S..." kubed-list-type)))) - -(defun kubed-list-delete-marked () - "Delete marked Kubernetes resources." - (interactive "" kubed-list-mode) - (let (delete-list) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (when (eq (char-after) ?D) - (push (tabulated-list-get-id) delete-list)) - (forward-line))) - (if delete-list - (when (y-or-n-p (format "Delete %d marked Kubernetes resources?" - (length delete-list))) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (when (member (tabulated-list-get-id) delete-list) - (tabulated-list-put-tag - (propertize "K" 'help-echo "Deletion in progress"))) - (forward-line))) - (let ((errb (generate-new-buffer " *kubed-list-delete-marked-stderr*")) - (buf (current-buffer))) - (make-process - :name "*kubed-list-delete-marked*" - :stderr errb - :command (cons kubed-kubectl-program - (append - (when kubed-list-context - (list "--context" kubed-list-context)) - (when kubed-list-namespace - (list "--namespace" kubed-list-namespace)) - (list "delete" kubed-list-type) - delete-list)) - :sentinel (lambda (_proc status) - (cond - ((string= status "finished\n") - (message (format "Deleted %d marked Kubernetes resources." - (length delete-list))) - (when (buffer-live-p buf) - (with-current-buffer buf - (kubed-list-update t)))) - ((string= status "exited abnormally with code 1\n") - (with-current-buffer errb - (goto-char (point-max)) - (insert "\n" status)) - (display-buffer errb))))))) - (user-error "No Kubernetes resources marked for deletion")))) - -(defun kubed-list-display-resource (click) - "Display Kubernetes resource at CLICK in another window." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (kubed-display-resource - kubed-list-type resource kubed-list-context kubed-list-namespace) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-select-resource (click) - "Display Kubernetes resource at CLICK in current window." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (switch-to-buffer - (kubed-display-resource-in-buffer - (concat "*Kubed " - (kubed-display-resource-short-description - kubed-list-type resource kubed-list-context kubed-list-namespace) - "*") - kubed-list-type resource kubed-list-context kubed-list-namespace)) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-select-resource-other-window (click) - "Display Kubernetes resource at CLICK in other window and select that window." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (switch-to-buffer-other-window - (kubed-display-resource-in-buffer - (concat "*Kubed " - (kubed-display-resource-short-description - kubed-list-type resource kubed-list-context kubed-list-namespace) - "*") - kubed-list-type resource kubed-list-context kubed-list-namespace)) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-delete (click) - "Delete Kubernetes resource at CLICK." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (when (y-or-n-p (format "Delete `%s'?" resource)) - (kubed-delete-resources kubed-list-type (list resource) - kubed-list-context kubed-list-namespace)) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-patch (click) - "Patch Kubernetes resource at CLICK." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (kubed-patch kubed-list-type resource - (kubed-read-patch) kubed-list-context kubed-list-namespace) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-edit (click) - "Edit Kubernetes resource at CLICK." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (kubed-edit-resource kubed-list-type resource - kubed-list-context kubed-list-namespace) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-kubectl-command (click) - "Use Kubernetes resource at CLICK as argument for `kubectl' command." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (kubed-kubectl-command - (kubed-read-kubectl-command - "Execute command: " - (cons (concat - " " - (when kubed-list-namespace (concat "-n " kubed-list-namespace " ")) - (when kubed-list-context (concat "--context " kubed-list-context " ")) - kubed-list-type " " resource) - ;; Put point after "kubectl ". - 0))) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-logs (click) - "Show logs for Kubernetes resource at CLICK." - (interactive (list last-nonmenu-event) kubed-list-mode) - (if-let ((resource (tabulated-list-get-id (mouse-set-point click)))) - (kubed-logs kubed-list-type resource kubed-list-context kubed-list-namespace - t t nil t) - (user-error "No Kubernetes resource at point"))) - -(defun kubed-list-create (definition &optional kind) - "Create Kubernetes resource of kind KIND from definition file DEFINITION." - (interactive (list (kubed-read-resource-definition-file-name)) kubed-list-mode) - (kubed-create definition kind kubed-list-context) - (kubed-list-update t)) - -(defun kubed-list-column-number-at-point () - "Return table column number at point." - (let ((start (current-column)) - (nb-cols (1- (length tabulated-list-format))) - (col-nb 0) - (total-width tabulated-list-padding) - (found nil)) - (while (and (not found) (< col-nb nb-cols)) - (if (>= start - (setq total-width - (+ total-width - (cadr (aref tabulated-list-format col-nb)) - (or (plist-get (nthcdr 3 (aref tabulated-list-format - col-nb)) - :pad-right) - 1)))) - (setq col-nb (1+ col-nb)) - (setq found t))) - col-nb)) - -(defun kubed-list-fit-column-width-to-content (n) - "Fit width of Nth table column to its content. - -If N is negative, fit all columns. Interactively, N is the column -number at point, or the numeric prefix argument if you provide one." - (interactive - (list (if current-prefix-arg - (prefix-numeric-value current-prefix-arg) - (kubed-list-column-number-at-point))) - kubed-list-mode) - (if (< n 0) - ;; Fit all columns. - (let* ((num-cols (length tabulated-list-format)) - (widths (apply #'vector (seq-map - ;; +2 to make room for sorting icon. - (lambda (col) (+ 2 (length (car col)))) - tabulated-list-format)))) - (save-excursion - (goto-char (point-min)) - (while-let ((entry (tabulated-list-get-entry))) - (dotimes (i num-cols) - (aset widths i (max (aref widths i) (length (aref entry i))))) - (forward-line))) - (setq tabulated-list-format (copy-tree tabulated-list-format t)) - (dotimes (i num-cols) - (setf (cadr (aref tabulated-list-format i)) - (1+ (aref widths i))))) - ;; Fit Nth column. - (let* ((width (+ 2 (length (car (aref tabulated-list-format n)))))) - (save-excursion - (goto-char (point-min)) - (while-let ((entry (tabulated-list-get-entry))) - (setq width (max width (length (aref entry n)))) - (forward-line))) - (setq tabulated-list-format (copy-tree tabulated-list-format t)) - (setf (cadr (aref tabulated-list-format n)) (1+ width)))) - (tabulated-list-print t) - (tabulated-list-init-header)) - -(declare-function kubed-list-transient "kubed-transient" ()) -(declare-function kubed-transient-logs-for-pod "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-deployment "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-statefulset "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-replicaset "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-daemonset "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-job "kubed-transient" (val)) -(declare-function kubed-transient-logs-for-service "kubed-transient" (val)) - -(defvar-keymap kubed-list-mode-map - :doc "Common keymap for Kubernetes resource list buffers." - "RET" #'kubed-list-select-resource - "o" #'kubed-list-select-resource-other-window - "C-o" #'kubed-list-display-resource - "D" #'kubed-list-delete - "P" #'kubed-list-patch - "x" #'kubed-list-delete-marked - "e" #'kubed-list-edit - "!" #'kubed-list-kubectl-command - "g" #'kubed-list-update - "/" #'kubed-list-set-filter - "|" #'kubed-list-fit-column-width-to-content - "d" #'kubed-list-mark-for-deletion - "u" #'kubed-list-unmark - "w" #'kubed-list-copy-as-kill - "C-i" #'kubed-list-next-column - "TAB" #'kubed-list-next-column - "C-S-i" #'kubed-list-previous-column - "S-TAB" #'kubed-list-previous-column - "" #'kubed-list-previous-column - "+" #'kubed-list-create - "?" #'kubed-list-transient) - -(defun kubed-list-entries () - "`tabulated-list-entries' function for `kubed-list-mode'." - (let ((pred (kubed-list-interpret-filter)) - (ents nil)) - (dolist (ent (alist-get 'resources (kubed--alist kubed-list-type - kubed-list-context - kubed-list-namespace))) - (when (funcall pred ent) (push ent ents))) - (reverse ents))) - -;;;###autoload -(defun kubed-list-handle-bookmark (bookmark) - "Display Kubernetes resource according to BOOKMARK." - (require 'bookmark) - (let* ((type (bookmark-prop-get bookmark 'type)) - (context (bookmark-prop-get bookmark 'context)) - (namespace (bookmark-prop-get bookmark 'namespace)) - (current (bookmark-prop-get bookmark 'current)) - (buff-fn (intern (format "kubed-%s-buffer" type))) - (buff (apply buff-fn context (when namespace (list namespace))))) - (set-buffer buff) - (when current (kubed-list-go-to-line current)))) - -(put 'kubed-list-handle-bookmark 'bookmark-handler-type "KubedList") - -(defun kubed-list-make-bookmark () - "Return bookmark pointing to currently displayed Kubernetes resource." - (require 'bookmark) - (cons - (concat kubed-list-type - (when kubed-list-namespace (concat "@" kubed-list-namespace)) - (when kubed-list-context (concat "[" kubed-list-context "]"))) - (append - (list - (cons 'handler #'kubed-list-handle-bookmark) - (cons 'filter kubed-list-filter) - (cons 'type kubed-list-type) - (cons 'context kubed-list-context) - (cons 'current (tabulated-list-get-id)) - (cons 'namespace kubed-list-namespace))))) - -(defun kubed-list-revert (&rest _) - "Revert the current Kubernetes resources list buffer. - -This is the `revert-buffer-function' for `kubed-list-mode' and its -derivatives. This function does not fetch new data from Kubernetes, it -only (re)displays the existing data." - (let (marks) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (unless (eq (char-after) ?\s) - (push (cons (tabulated-list-get-id) - ;; Preserve mark text properties. - (buffer-substring (point) (1+ (point)))) - marks)) - (forward-line))) - (tabulated-list-revert) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (let ((id (tabulated-list-get-id))) - (when-let ((mark (alist-get id marks nil nil #'equal))) - (tabulated-list-put-tag mark))) - (forward-line))))) - -(define-derived-mode kubed-list-mode tabulated-list-mode "Kubernetes Resources" - "Major mode for listing Kubernetes resources. - -Modes for specific resource types, such as `kubed-pods-mode', use this -mode as their parent." - :interactive nil - (setq-local truncate-string-ellipsis (propertize ">" 'face 'shadow) - tabulated-list-entries #'kubed-list-entries - bookmark-make-record-function #'kubed-list-make-bookmark - revert-buffer-function #'kubed-list-revert) - (add-hook 'context-menu-functions #'kubed-list-context-menu nil t)) - -;;;###autoload -(defun kubed-delete-resources (type resources context &optional namespace) - "Delete Kubernetes RESOURCES of type TYPE in context CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCES. With a prefix argument \ -\\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \ -\\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well." - (interactive - (let ((type nil) (context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-delete)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless type - (setq type (kubed-read-resource-type "Type of resource to delete" - nil context))) - (when (and (null namespace) (kubed-namespaced-p type context)) - (setq namespace (kubed--namespace context current-prefix-arg))) - (list type (kubed-read-resource-name type "Delete" nil t - context namespace) - context namespace))) - (unless resources (user-error "You didn't specify %s to delete" type)) - (message (format "Deleting Kubernetes %s `%s'..." - type (string-join resources "', `"))) - (if (zerop (apply #'call-process - kubed-kubectl-program nil nil nil - "delete" type - (append (when namespace (list "-n" namespace)) - (when context (list "--context" context)) - resources))) - (message (format "Deleting Kubernetes %s `%s'... Done." - type (string-join resources "', `"))) - (error (format "Failed to delete Kubernetes %s `%s'" - type (string-join resources "', `"))))) - -;;;###autoload -(defun kubed-edit-resource (type resource context &optional namespace) - "Edit Kubernetes RESOURCE of type TYPE in context CONTEXT. - -For namespaced resource types, NAMESPACE is the namespace of RESOURCE. - -Interactively, use the current context and namespace by default, and -prompt for TYPE and RESOURCES. With a prefix argument \ -\\[universal-argument], -prompt for NAMESPACE. With a double prefix argument \ -\\[universal-argument] \\[universal-argument], -prompt for CONTEXT as well." - (interactive - (let ((type nil) (context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-edit)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless type - (setq type (kubed-read-resource-type "Type of resource to edit" - nil context))) - (when (and (null namespace) (kubed-namespaced-p type context)) - (setq namespace (kubed--namespace context current-prefix-arg))) - (list type (kubed-read-resource-name type "Edit" nil nil - context namespace) - context namespace))) - (unless (bound-and-true-p server-process) (server-start)) - (let ((process-environment - (cons (if (boundp 'emacsclient-program-name) - (concat "KUBE_EDITOR=" emacsclient-program-name) - "KUBE_EDITOR=emacsclient") - process-environment))) - (apply #'start-process - (format "*kubed-%S-edit*" type) nil - kubed-kubectl-program "edit" type resource - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context)))))) - -(defcustom kubed-list-mode-line-format - '(:eval (cond - ((process-live-p - (alist-get 'process - (kubed--alist kubed-list-type - kubed-list-context - kubed-list-namespace))) - (propertize "[...]" 'help-echo "Updating...")) - (kubed-list-filter - (propertize - (concat "[" (mapconcat #'prin1-to-string kubed-list-filter " ") "]") - 'help-echo "Current filter")))) - "Mode line construct for indicating status of Kubernetes resources list." - :type 'sexp - :risky t) - -;;;###autoload -(defmacro kubed-define-resource (resource &optional properties &rest commands) - "Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS. - -RESOURCE is a symbol corresponding to a Kubernetes resource type, such -as `pod' or `service'. This macro defines the following commands for -interacting with Kubernetes RESOURCEs: - -- `kubed-display-RESOURCE': prompt for a RESOURCE and display its - description in YAML format. See also `kubed-yaml-setup-hook'. -- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it. -- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it. -- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the - current namespace. The RESOURCEs list buffer uses a dedicated major - mode, `kubed-RESOURCEs-mode', which is also defined by this macro. -- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file. -- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs. - -This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map', -with bindings for the above commands. - -PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS) -that specify properties of RESOURCEs. PROP is the name of the property, -as a symbol; JSON-PATH is a JSONPath expression that evaluates to the -value of PROP when applied to the JSON representation of a RESOURCE. -WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted. WIDTH is -used as the default width of the column corresponding to PROP in -RESOURCEs list buffers; SORT is sort predicate, a function that takes -two values of PROP as strings and returns non-nil if the first should -sort before the second; FORMAT is a function that takes a value of PROP -and formats it. If you provide a FORMAT function and a SORT function, -then the SORT function gets the formatted values (the output of the -FORMAT function), not the original values. If you want to sort based on -the unformatted original values, you can store them as text properties -in your FORMAT function and access them in your SORT function. - -ATTRS is a plist of additional attributes of the PROP column, see -`tabulated-list-format' for available attributes. - -For example, if PROPERTIES is (phase \".status.phase\" 10) that means -that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose -values are typically 10 columns wide. The first property in PROPERTIES -is used to annotate completion candidates when prompting for a RESOURCE. - -COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that -define commands for RESOURCE list buffers. COMMAND is a symbol -specifying the suffix of the command name, the full name of the command -is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is -either a string that specifies a key sequence to bind to the command in -`kubed-RESOURCEs-mode-map', or nil if the command should not be bound; -DOC-PREFIX is a string used to construct the docstring of the command, -this macro appends the string \" Kubernetes RESOURCE at point.\" to it -to obtain the final docstring; lastly, BODY is the body the command. -Within BODY, the variable RESOURCE is let-bound to the name of the -RESOURCE at point. For example, if RESOURCE is `pod', the following -COMMANDS element defines a command `kubed-pods-frob' and binds it to the -key \"f\" in `kubed-pods-mode-map': - - (frob \"f\" \"Frobnicate\" - (message \"Preparing...\") - (frobnicate-pod pod) - (message \"Done.\")) - -By default, this macro assumes that RESOURCE is namespaced. To define a -namespaceless resource type, put `:namespaced nil' before COMMANDS: - - (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil - CMD1 - CMD2 - ...) - -Other keyword arguments that go between PROPERTIES and COMMANDS are: - -- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the - resource creation command, `kubed-create-RESOURCE'. ARGLIST, - DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'. -- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the - prefix keymap `kubed-RESOURCE-prefix-map' and the - `kubed-RESOURCE-menu-map' menu. Each element (KEY LABEL DEFINITION) - says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to - add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL. -- `:plural PLURAL': specify plural form of RESOURCE, as a symbol. If - you omit this keyword argument, the plural form defaults to RESOURCE - followed by \"s\". -- `:logs t': generate `kubed-logs-for-RESOURCE' command. -- `:suffixes (SUFFIX...)': add type-specific transient suffixes to - `kubed-list-transient'." - (declare (indent 2)) - (let ((plrl-var (intern (format "%Ss" resource))) - (read-fun (intern (format "kubed-read-%S" resource))) - (dsp-name (intern (format "kubed-display-%S" resource))) - (edt-name (intern (format "kubed-edit-%S" resource))) - (crt-name (intern (format "kubed-create-%S" resource))) - (map-name (intern (format "kubed-%S-prefix-map" resource))) - (menu-map (intern (format "kubed-%S-menu-map" resource))) - (logs-cmd (intern (format "kubed-logs-for-%S" resource))) - (logs-trs (intern (format "kubed-transient-logs-for-%S" resource))) - (namespaced t) (logs nil) - (keyword nil) - frmt-var buff-fun list-cmd expl-cmd dlt-name mod-name - ctxt-fun crt-spec prf-keys hist-var trs-cols) - - ;; Process keyword arguments. - (while (keywordp (car commands)) - (setq keyword (pop commands)) - (cond - ((eq keyword :namespaced) (setq namespaced (pop commands))) - ((eq keyword :logs) (setq logs (pop commands))) - ((eq keyword :create) (setq crt-spec (pop commands))) - ((eq keyword :prefix) (setq prf-keys (pop commands))) - ((eq keyword :plural) (setq plrl-var (pop commands))) - ((eq keyword :suffixes) (setq trs-cols (pop commands))) - ;; FIXME: Add error for unknown keywords. - (t (pop commands)))) - - (setq frmt-var (intern (format "kubed-%S-columns" plrl-var)) - hist-var (intern (format "kubed-%S-history" plrl-var)) - buff-fun (intern (format "kubed-%S-buffer" plrl-var)) - list-cmd (intern (format "kubed-list-%S" plrl-var)) - expl-cmd (intern (format "kubed-explain-%S" plrl-var)) - dlt-name (intern (format "kubed-delete-%S" plrl-var)) - mod-name (intern (format "kubed-%S-mode" plrl-var)) - ctxt-fun (intern (format "kubed-%S-context-menu" plrl-var))) - - (when logs (push `("L" "Show Logs" ,logs-cmd) prf-keys)) - - ;; Generate code. - `(progn - (setf (alist-get ,(symbol-name plrl-var) kubed--columns nil nil #'string=) - (list - '("NAME:.metadata.name") - ,@(mapcar (lambda (p) - `(cons ,(concat (upcase (symbol-name (car p))) - ":" - (cadr p)) - ,(nth 4 p))) - properties))) - - (defvar ,hist-var nil - ,(format "History list for `%S'." read-fun)) - - (defun ,read-fun (prompt &optional default multi context - . ,(when namespaced '(namespace))) - ,(format "Prompt with PROMPT for a Kubernetes %S name. - -Optional argument DEFAULT is the minibuffer default argument. - -Non-nil optional argument MULTI says to read and return a list -of %S, instead of just one." resource plrl-var) - (kubed-read-resource-name ,(symbol-name plrl-var) prompt default multi context . ,(when namespaced '(namespace)))) - - (defun ,dsp-name (,resource &optional context . ,(when namespaced '(namespace))) - ,(if namespaced - (format "Display Kubernetes %S %s in CONTEXT and NAMESPACE. - -Interactively, use the current context and namespace by default. With a -prefix argument \\[universal-argument], prompt for NAMESPACE. With a -double prefix argument \\[universal-argument] \\[universal-argument], \ -prompt for CONTEXT as well." resource (upcase (symbol-name resource))) - (format "Display Kubernetes %S %s in context CONTEXT. - -Interactively, use the current context. With a prefix argument -\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource)))) - (interactive - ,(if namespaced - `(let ((context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-display)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (,read-fun "Display" nil nil context namespace) context namespace)) - `(let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-display)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (list (,read-fun "Display" nil nil context) context)))) - (let ((context (or context (kubed-local-context)))) - (kubed-display-resource - ,(symbol-name plrl-var) ,resource context - . ,(when namespaced '((or namespace (kubed--namespace context))))))) - - (defun ,edt-name (,resource &optional context . ,(when namespaced '(namespace))) - ,(if namespaced - (format "Edit Kubernetes %S %s in CONTEXT and NAMESPACE. - -Interactively, use the current context and namespace by default. With a -prefix argument \\[universal-argument], prompt for NAMESPACE. With a -double prefix argument \\[universal-argument] \\[universal-argument], \ -prompt for CONTEXT as well." resource (upcase (symbol-name resource))) - (format "Edit Kubernetes %S %s in context CONTEXT. - -Interactively, use the current context. With a prefix argument -\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource)))) - (interactive - ,(if namespaced - `(let ((context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-edit)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (,read-fun "Edit" nil nil context namespace) context namespace)) - `(let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-edit)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (list (,read-fun "Edit" nil nil context) context)))) - (let ((context (or context (kubed-local-context)))) - (kubed-edit-resource - ,(symbol-name plrl-var) ,resource context - . ,(when namespaced '((or namespace (kubed--namespace context))))))) - - (defun ,dlt-name (,plrl-var &optional context - . ,(when namespaced '(namespace))) - ,(if namespaced - (format "Delete Kubernetes %S %s in CONTEXT and NAMESPACE. - -Interactively, use the current context and namespace by default. With a -prefix argument \\[universal-argument], prompt for NAMESPACE. With a -double prefix argument \\[universal-argument] \\[universal-argument], \ -prompt for CONTEXT as well." plrl-var (upcase (symbol-name plrl-var))) - (format "Delete Kubernetes %S %s in context CONTEXT. - -Interactively, use the current context. With a prefix argument -\\[universal-argument], prompt for CONTEXT." plrl-var (upcase (symbol-name plrl-var)))) - (interactive - ,(if namespaced - `(let ((context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-delete)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (,read-fun "Delete" nil t context namespace) context namespace)) - `(let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-delete)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (list (,read-fun "Delete" nil t context) context)))) - (unless ,plrl-var - (user-error ,(format "You didn't specify %S to delete" plrl-var))) - (let ((context (or context (kubed-local-context)))) - (kubed-delete-resources - ,(symbol-name plrl-var) ,plrl-var context - . ,(when namespaced '((or namespace (kubed--namespace context))))))) - - ,(if crt-spec `(defun ,crt-name . ,crt-spec) - `(defun ,crt-name (definition &optional context) - ,(format "Create Kubernetes %s from file DEFINITION in CONTEXT. - -Interactively, prompt for DEFINITION and use the current context. With -a prefix argument \\[universal-argument], prompt for CONTEXT too." - (symbol-name resource)) - (interactive - (let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (list (kubed-read-resource-definition-file-name ,(symbol-name resource)) - context))) - (kubed-create definition ,(symbol-name resource) context) - (kubed-update ,(symbol-name plrl-var) context))) - - ,@(when logs - `((defun ,logs-cmd - ( ,resource &optional context namespace - container follow limit prefix since tail timestamps) - ,(format "Show logs for Kubernetes %S %s." - resource (upcase (symbol-name resource))) - (interactive - (let ( ,resource context namespace - container follow limit prefix since tail timestamps) - (dolist (arg (kubed-transient-args - ',logs-trs)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--limit-bytes=\\(.+\\)" arg) - (setq limit (string-to-number (match-string 1 arg)))) - ((string-match "--tail=\\(.+\\)" arg) - (setq tail (string-to-number (match-string 1 arg)))) - ((string-match "--since-time=\\(.+\\)" arg) - (setq since (match-string 1 arg))) - ((equal "--all-containers" arg) (setq container t)) - ((equal "--follow" arg) (setq follow t)) - ((equal "--prefix" arg) (setq prefix t)) - ((equal "--timestamps" arg) (setq timestamps t)))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (setq ,resource (,read-fun "Show logs for" - (and (equal context kubed-list-context) - (equal namespace kubed-list-namespace) - (equal ,(symbol-name plrl-var) kubed-list-type) - (tabulated-list-get-id (mouse-set-point last-nonmenu-event))) - nil context namespace)) - (list ,resource context namespace - ,(if (eq resource 'pod) - '(or container - (kubed-read-container pod "Container" t - context namespace)) - 'container) - follow limit prefix since tail timestamps))) - (kubed-logs ,(symbol-name plrl-var) ,resource context namespace container - follow limit prefix since tail timestamps)))) - - ,@(let ((click-var (gensym "click"))) - (mapcar - (pcase-lambda (`(,suffix ,_key ,desc . ,body)) - `(defun ,(intern (format "kubed-%S-%S" plrl-var suffix)) (,click-var) - ,(format "%s Kubernetes %S at point." desc resource) - (interactive (list last-nonmenu-event) ,mod-name) - (if-let ((,resource (tabulated-list-get-id (mouse-set-point ,click-var)))) - (progn ,@body) - (user-error ,(format "No Kubernetes %S at point" resource))))) - commands)) - - (defvar-keymap ,(intern (format "kubed-%S-mode-map" plrl-var)) - :doc ,(format "Keymap for `%S" mod-name) - "+" #',crt-name - ,@(when logs - `("l" #'kubed-list-logs - "L" #',logs-trs)) - ,@(mapcan - (pcase-lambda (`(,suffix ,key ,_desc . ,_body)) - (when key - (list key `#',(intern (format "kubed-%S-%S" plrl-var suffix))))) - commands)) - - (defvar ,frmt-var - ',(let ((i 0) - (res nil)) - (dolist (p properties) - (setq i (1+ i)) - (push - (append - (list (capitalize (symbol-name (car p))) - (caddr p) - (if-let ((sorter (cadddr p))) - `(lambda (l r) - (funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i))) - t)) - (nthcdr 5 p)) - res)) - (reverse res))) - - (defun ,ctxt-fun (menu . ,(if commands '(click) '(_click))) - ,@(when commands - `((when (tabulated-list-get-entry (posn-point (event-start click))) - ,@(mapcar - (pcase-lambda (`(,suffix ,_key ,desc . ,_body)) - `(define-key - menu [,(intern (format "kubed-%S-%S" plrl-var suffix))] - (list 'menu-item ,(format "%s this %S" desc resource) - #',(intern (format "kubed-%S-%S" plrl-var suffix))))) - (reverse commands))))) - menu) - - (define-derived-mode ,mod-name kubed-list-mode - '(,(format "Kubernetes %s" (capitalize (symbol-name plrl-var))) - kubed-list-mode-line-format) - ,(format "Major mode for listing Kubernetes %S." plrl-var) - :interactive nil - (setq kubed-list-filter-history-variable - ',(intern (format "kubed-%S-filter-history" plrl-var)) - kubed-list-type ,(symbol-name plrl-var) - ,@(when trs-cols - `(kubed-list-transient-extra-suffixes ',trs-cols)) - tabulated-list-padding 2 - tabulated-list-format (apply #'vector (cons kubed-name-column ,frmt-var))) - (add-hook 'context-menu-functions #',ctxt-fun nil t) - (tabulated-list-init-header)) - - (defun ,buff-fun (context . ,(when namespaced '(namespace))) - (let ((buf-name (format ,(format "*Kubed %S%%s*" plrl-var) - ,(if namespaced - `(concat "@" namespace "[" context "]") - `(concat "[" context "]"))))) - (if-let ((buf (get-buffer buf-name))) buf - (with-current-buffer (get-buffer-create buf-name) - (,mod-name) - (setq kubed-list-context context - ,@(when namespaced - '(kubed-list-namespace namespace))) - (kubed-list-update) - (tabulated-list-print) - (current-buffer))))) - - (defun ,list-cmd (context . ,(when namespaced '(namespace))) - ,(if namespaced - (format "List Kubernetes %S in context CONTEXT and namespace NAMESPACE. - -Interactively, use the current context and namespace by default. With a -prefix argument \\[universal-argument], prompt for NAMESPACE. With a -double prefix argument \\[universal-argument] \\[universal-argument], \ -prompt for CONTEXT as well." plrl-var) - (format "List Kubernetes %S in context CONTEXT. - -Interactively, use the current context. With a prefix argument -\\[universal-argument], prompt for CONTEXT." plrl-var)) - (interactive - (let* ((context (kubed-local-context)) - (context (if (equal current-prefix-arg - ,(if namespaced ''(16) ''(4))) - (kubed-read-context "Context" context) - context))) - (list context - . ,(when namespaced '((kubed--namespace context current-prefix-arg)))))) - (pop-to-buffer (,buff-fun context . ,(when namespaced '(namespace))))) - - (defun ,expl-cmd () - ,(format "Show help buffer with explanation about Kubernetes %S." plrl-var) - (interactive) - (kubed-explain ,(symbol-name plrl-var))) - - (defvar-keymap ,map-name - :doc ,(format "Prefix keymap for Kubed %S commands." resource) - :prefix ',map-name - "l" #',list-cmd - "+" #',crt-name - "e" #',edt-name - "d" #',dlt-name - "RET" #',dsp-name - "E" #',expl-cmd - ,@(mapcan - (pcase-lambda (`(,key ,_label ,cmd)) - (list key `#',cmd)) - prf-keys)) - - (defvar-keymap ,menu-map - :doc ,(format "Keymap with Kubernetes %S related menu entries." resource) - :prefix ',menu-map - "" '("List" . ,list-cmd) - "" '("Create" . ,crt-name) - "" '("Edit" . ,edt-name) - "" '("Delete" . ,dlt-name) - "" '("Display" . ,dsp-name) - "" '("Explain Fields" . ,expl-cmd) - ,@(mapcan - (pcase-lambda (`(,key ,label ,cmd)) - (list key `'(,label . ,cmd))) - prf-keys))))) - -(setf - ;; Teach Imenu about `kubed-define-resource'. - (alist-get "KubedResource" lisp-imenu-generic-expression nil nil #'equal) - (list (concat "^\\s-*(kubed-define-resource\\s-+\\(" - lisp-mode-symbol-regexp - "\\)") - 1)) - -(defconst kubed--hex-encoding-table - (let ((vec (make-vector 256 nil))) - (dotimes (byte 256) (aset vec byte (format ".%02X" byte))) vec)) - -(defconst kubed--hex-allowed-chars-table - (let ((vec (make-vector 256 nil))) - (dolist (byte '( ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z - ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z - ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 - ?- ?_)) - (ignore-errors (aset vec byte t))) - vec)) - -(defun kubed--encode-context-name (str) - ;; Adopted from `url-hexify-string'. - (mapconcat (lambda (byte) - (if (aref kubed--hex-allowed-chars-table byte) - (char-to-string byte) - (aref kubed--hex-encoding-table byte))) - (if (multibyte-string-p str) - (encode-coding-string str 'utf-8) - str))) - -(defun kubed-remote-file-name (context namespace pod &optional file-name) - "Return remote FILE-NAME for POD in NAMESPACE and CONTEXT." - (concat "/" kubed-tramp-method ":" - (kubed--encode-context-name context) "%" namespace "%" pod - "%" (kubed-read-container pod "Container" t context namespace) - ":" file-name)) - -(declare-function kubed-tramp-context "kubed-tramp" (file-name)) -(declare-function kubed-tramp-namespace "kubed-tramp" (file-name)) -(declare-function kubed-tramp-assert-support "kubed-tramp" ()) - -;;;###autoload (autoload 'kubed-display-pod "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-pod "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-pods "kubed" nil t) -;;;###autoload (autoload 'kubed-list-pods "kubed" nil t) -;;;###autoload (autoload 'kubed-create-pod "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-pod "kubed" nil t) -;;;###autoload (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource pod - ((phase ".status.phase" 10 - nil ; sorting function - (lambda (ph) - (if-let ((face (pcase ph - ;; TODO: Define/derive bespoke faces. - ("Pending" 'warning) - ("Running" 'success) - ("Succeeded" 'shadow) - ("Failed" 'error)))) - (propertize ph 'face face) - ph))) - (ready ".status.containerStatuses[?(.ready==true)].name" 6 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - (lambda (cs) - (if (string= cs "") "0" - (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs))))) - :right-align t) - (total ".status.containerStatuses[*].name" 6 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - (lambda (cs) - (if (string= cs "") "0" - (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs))))) - :right-align t) - (starttime ".status.startTime" 20)) - :logs t - :prefix (("A" "Attach" kubed-attach) - ("X" "Execute" kubed-exec) - ("F" "Forward Port" kubed-forward-port-to-pod)) - :suffixes ([ ("L" "Logs" kubed-transient-logs-for-pod) - ("X" "Exec" kubed-pods-exec) - ("a" "Attach" kubed-pods-attach)] - [ :pad-keys t - ("C-d" "Dired" kubed-pods-dired) - ("s" "Shell" kubed-pods-shell) - ("F" "Forward port" kubed-pods-forward-port)]) - (dired "C-d" "Start Dired in" - (kubed-tramp-assert-support) - (dired (kubed-remote-file-name - kubed-list-context kubed-list-namespace pod))) - (shell "s" "Start shell in" - (kubed-tramp-assert-support) - (let* ((default-directory (kubed-remote-file-name - kubed-list-context kubed-list-namespace pod))) - (shell - (concat "*Kubed Shell " - (kubed-display-resource-short-description - "pods" pod kubed-list-context kubed-list-namespace) - "*")))) - (attach "a" "Attach to remote process running on" - (kubed-attach pod (kubed-read-container pod "Container" t - kubed-list-context - kubed-list-namespace) - kubed-list-context kubed-list-namespace t t)) - (exec "X" "Execute command in" - (let ((container (kubed-read-container pod "Container" t - kubed-list-context - kubed-list-namespace)) - (cmd-args (split-string-and-unquote - (read-string "Execute command: ")))) - (kubed-exec pod (car cmd-args) container kubed-list-context - kubed-list-namespace t t (cdr cmd-args)))) - (forward-port "F" "Forward local network port to remote port of" - (let ((local-port (read-number "Forward local port: "))) - (kubed-forward-port-to-pod - pod local-port - (read-number (format "Forward local port %d to remote port: " - local-port)) - kubed-list-context - kubed-list-namespace)))) - -;;;###autoload (autoload 'kubed-display-namespace "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-namespace "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-namespaces "kubed" nil t) -;;;###autoload (autoload 'kubed-list-namespaces "kubed" nil t) -;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t) -;;;###autoload (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource namespace - ((phase ".status.phase" 10 - nil ; sorting function - (lambda (ph) - (if-let ((face (pcase ph - ;; TODO: Define/derive bespoke faces. - ("Active" 'success) - ("Terminating" 'shadow)))) - (propertize ph 'face face) - ph))) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :namespaced nil - :prefix (("S" "Set" kubed-set-namespace)) - :create - ((name &optional context) - "Create Kubernetes namespace NAME in CONTEXT. - -Interactively, prompt for NAME and use the current context by default. -With a prefix argument, prompt for CONTEXT instead." - (interactive - (let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (list (read-string "Create namespace with name: ") context))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "create" "namespace" name - (when context (list "--context" context)))) - (user-error "Failed to create Kubernetes namespace with name `%s'" name)) - (kubed-update "namespaces" (or context (kubed-local-context))) - (message "Created Kubernetes namespace with name `%s'." name)) - (set "s" "Set current namespace to" - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (when (eq (char-after) ?*) - (tabulated-list-put-tag " ")) - (forward-line))) - (kubed-set-namespace namespace kubed-list-context) - (tabulated-list-put-tag - (propertize "*" 'help-echo "Current namespace")))) - -;;;###autoload (autoload 'kubed-display-persistentvolume "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-persistentvolume "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-persistentvolumes "kubed" nil t) -;;;###autoload (autoload 'kubed-list-persistentvolumes "kubed" nil t) -;;;###autoload (autoload 'kubed-create-persistentvolume "kubed" nil t) -;;;###autoload (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource persistentvolume () :namespaced nil) - -;;;###autoload (autoload 'kubed-display-service "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-service "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-services "kubed" nil t) -;;;###autoload (autoload 'kubed-list-services "kubed" nil t) -;;;###autoload (autoload 'kubed-create-service "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-service "kubed" nil t) -;;;###autoload (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource service - ((type ".spec.type" 12) - (clusterip ".spec.clusterIP" 16) - (externalip ".spec.externalIPs[*]" 16) - (ports ".spec.ports[*].port" 6) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :logs t) - -;;;###autoload (autoload 'kubed-display-secret "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-secret "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-secrets "kubed" nil t) -;;;###autoload (autoload 'kubed-list-secrets "kubed" nil t) -;;;###autoload (autoload 'kubed-create-secret "kubed" nil t) -;;;###autoload (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource secret - ((type ".type" 32) (creationtimestamp ".metadata.creationTimestamp" 20))) - -(defun kubed-create-job-from-cronjob (name cronjob &optional context namespace) - "Create Kubernetes job with name NAME from cronjob CRONJOB. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace to use for the job, -defaulting to the current namespace." - (interactive - (let ((name (read-string "Create job with name: ")) - (context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create-job)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list name - (kubed-read-cronjob - (format "Create job `%s' from cronjob" name) nil nil context namespace) - context namespace))) - (let* ((context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context)))) - (unless (zerop - (call-process - kubed-kubectl-program nil nil nil - "create" "job" name "--from" (concat "cronjob/" cronjob) - "-n" namespace "--context" context)) - (user-error "Failed to create Kubernetes job `%s'" name)) - (kubed-update "jobs" context namespace) - (message "Created Kubernetes job `%s'." name))) - -;;;###autoload (autoload 'kubed-display-job "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-job "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-jobs "kubed" nil t) -;;;###autoload (autoload 'kubed-list-jobs "kubed" nil t) -;;;###autoload (autoload 'kubed-create-job "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-job "kubed" nil t) -;;;###autoload (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource job - ((status ".status.conditions[0].type" 10) (starttime ".status.startTime" 20)) - :prefix (("c" "Create from Cron" kubed-create-job-from-cronjob)) - :logs t - :create - ((name image &optional context namespace command) - "Create Kubernetes job with name NAME executing COMMAND in IMAGE. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace to use for the job, -defaulting to the current namespace." - (interactive - (let ((name (read-string "Create job with name: ")) - (image nil) (context nil) (namespace nil) (command nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create-job)) - (cond - ((string-match "--image=\\(.+\\)" arg) - (setq image (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "-- =\\(.+\\)" arg) - (setq command (split-string-and-unquote (match-string 1 arg)))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (unless image - (setq image (kubed-read-container-image "Image to run in job"))) - (list name image context namespace command))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "create" "job" name "--image" image - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context)) - (when command (cons "--" command))))) - (user-error "Failed to create Kubernetes job `%s'" name)) - (message "Created Kubernetes job `%s'." name))) - -;;;###autoload -(defun kubed-watch-deployment-status (dep &optional context namespace cb) - "Show and update status of Kubernetes deployment DEP in a dedicate buffer. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. CB is an optional callback function to call with -no arguments when the deployment ends. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." - (interactive - (let (context namespace) - (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (kubed-read-deployment "Watch deployment status" nil nil - context namespace) - context namespace))) - (let* ((buf (get-buffer-create "*kubed-deployment-status*")) - (context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context)))) - (with-current-buffer buf (erase-buffer)) - (make-process - :name "*kubed-watch-deployment-status*" - :buffer buf - :command (list kubed-kubectl-program "rollout" "status" - "deployment" dep "-n" namespace "--context" context) - :sentinel (when cb - (lambda (_proc status) - (when (member status '("finished\n" - "exited abnormally with code 1\n")) - (funcall cb))))) - (display-buffer buf))) - -(defcustom kubed-restart-deployment-watch-status t - "Whether to pop up a progress buffer when restarting Kubernetes deployments." - :type 'boolean) - -;;;###autoload -(defun kubed-scale-deployment (dep reps &optional context namespace) - "Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." - (interactive - (let (reps context namespace) - (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--replicas=\\(.+\\)" arg) - (setq reps (string-to-number (match-string 1 arg)))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (kubed-read-deployment "Scale deployment" nil nil context namespace) - (or reps (read-number "Number of replicas: ")) context namespace))) - (let* ((context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context)))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "scale" "deployment" dep - "--replicas" (number-to-string reps) - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context))))) - (user-error "Failed to scale Kubernetes deployment `%s'" dep)) - (message "Scaled Kubernetes deployment `%s' to %d replicas." dep reps))) - -;;;###autoload -(defun kubed-restart-deployment (dep &optional context namespace) - "Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; NAMESPACE is the namespace of DEP, defaulting to -the current namespace. CB is an optional callback function to call with -no arguments when the deployment ends. - -Interactively, prompt for DEP. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." - (interactive - (let (context namespace) - (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (kubed-read-deployment "Restart deployment" nil nil - context namespace) - context namespace))) - (let* ((context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context)))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "rollout" "restart" "deployment" dep - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context))))) - (user-error "Failed to restart Kubernetes deployment `%s'" dep)) - (message "Restarting Kubernetes deployment `%s'." dep) - (when kubed-restart-deployment-watch-status - (kubed-watch-deployment-status - dep context namespace - (lambda () - (kubed-update "deployments" context namespace)))))) - -;;;###autoload (autoload 'kubed-display-deployment "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-deployment "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-deployments "kubed" nil t) -;;;###autoload (autoload 'kubed-list-deployments "kubed" nil t) -;;;###autoload (autoload 'kubed-create-deployment "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-deployment "kubed" nil t) -;;;###autoload (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource deployment - (( ready ".status.readyReplicas" 6 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - (lambda (s) (if (string= s "") "0" s)) - :right-align t) - ( updated ".status.updatedReplicas" 8 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - (lambda (s) (if (string= s "") "0" s)) - :right-align t) - ( available ".status.availableReplicas" 10 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - (lambda (s) (if (string= s "") "0" s)) - :right-align t) - ( reps ".status.replicas" 4 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - ( creationtimestamp ".metadata.creationTimestamp" 20)) - :prefix (("R" "Restart" kubed-restart-deployment) - ("W" "Watch" kubed-watch-deployment-status) - ("$" "Scale" kubed-scale-deployment)) - :logs t - :suffixes ([("L" "Logs" kubed-transient-logs-for-deployment) - ("W" "Watch" kubed-deployments-watch) - ("R" "Restart" kubed-deployments-restart) - ("$" "Scale" kubed-deployments-scale)]) - :create - ((name images &optional context namespace replicas port command) - "Deploy IMAGES to Kubernetes in deployment with name NAME. - -Optional argument NAMESPACE is the namespace to use for the deployment, -defaulting to the current namespace, REPLICAS in the number of replicas -to create for each image, PORT is the port to expose, and COMMAND is an -optional command to run in the images." - (interactive - (let ((name (read-string "Create deployment with name: ")) - (images nil) (replicas nil) (port nil) (command nil) - (context nil) (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create-deployment)) - (cond - ((string-match "--replicas=\\(.+\\)" arg) - (setq replicas (string-to-number (match-string 1 arg)))) - ((string-match "--image=\\(.+\\)" arg) - (push (match-string 1 arg) images)) - ((string-match "--port=\\(.+\\)" arg) - (setq port (string-to-number (match-string 1 arg)))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "-- =\\(.+\\)" arg) - (setq command (split-string-and-unquote (match-string 1 arg)))))) - (unless images - (setq images (kubed-read-container-image "Images to deploy" nil t))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list name images context namespace replicas port command))) - (let* ((context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context)))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "create" "deployment" name - (append - (mapcar (lambda (image) (concat "--image=" image)) images) - (when namespace (list (concat "--namespace=" namespace))) - (when context (list (concat "--context=" context))) - (when replicas (list (format "--replicas=%d" replicas))) - (when port (list (format "--port=%d" port))) - (when command (cons "--" command))))) - (user-error "Failed to create Kubernetes deployment `%s'" name)) - (message "Created Kubernetes deployment `%s'." name) - (kubed-update "deployments" context namespace))) - (restart "R" "Restart" - (kubed-restart-deployment deployment kubed-list-context kubed-list-namespace) - (unless kubed-restart-deployment-watch-status - (message "Deployment restarting") - (kubed-list-update t))) - (watch "W" "Watch" (kubed-watch-deployment-status - deployment kubed-list-context kubed-list-namespace)) - (scale "$" "Scale" (kubed-scale-deployment - deployment (if current-prefix-arg - (prefix-numeric-value current-prefix-arg) - (read-number "Number of replicas: ")) - kubed-list-context kubed-list-namespace))) - -;;;###autoload (autoload 'kubed-display-replicaset "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-replicaset "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-replicasets "kubed" nil t) -;;;###autoload (autoload 'kubed-list-replicasets "kubed" nil t) -;;;###autoload (autoload 'kubed-create-replicaset "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-replicaset "kubed" nil t) -;;;###autoload (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource replicaset - ((reps ".status.replicas" 4 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (ownerkind ".metadata.ownerReferences[0].kind" 12) - (ownername ".metadata.ownerReferences[0].name" 16) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :logs t) - -;;;###autoload (autoload 'kubed-display-daemonset "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-daemonset "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-daemonsets "kubed" nil t) -;;;###autoload (autoload 'kubed-list-daemonsets "kubed" nil t) -;;;###autoload (autoload 'kubed-create-daemonset "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-daemonset "kubed" nil t) -;;;###autoload (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource daemonset - ((desired ".status.desiredNumberScheduled" 8 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (current ".status.currentNumberScheduled" 8 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (ready ".status.numberReady" 6 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (updated ".status.updatedNumberScheduled" 8 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (available ".status.numberAvailable" 10 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :logs t) - -;;;###autoload (autoload 'kubed-display-statefulset "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-statefulset "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-statefulsets "kubed" nil t) -;;;###autoload (autoload 'kubed-list-statefulsets "kubed" nil t) -;;;###autoload (autoload 'kubed-create-statefulset "kubed" nil t) -;;;###autoload (autoload 'kubed-logs-for-statefulset "kubed" nil t) -;;;###autoload (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource statefulset - ((reps ".status.replicas" 4 - (lambda (l r) (< (string-to-number l) (string-to-number r))) - nil ; formatting function - :right-align t) - (ownerkind ".metadata.ownerReferences[0].kind" 12) - (ownername ".metadata.ownerReferences[0].name" 16) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :logs t) - -(defun kubed-cronjob-suspended-p (cj &optional context ns) - "Return non-nil if cronjob CJ in CONTEXT and namespace NS is suspended." - (equal (car (apply #'process-lines - kubed-kubectl-program - "get" "cronjobs" cj - "-o" "custom-columns=SUSPENDED:.spec.suspend" "--no-headers" - (append - (when ns (list "-n" ns)) - (when context (list "--context" context))))) - "true")) - -;;;###autoload (autoload 'kubed-display-cronjob "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-cronjob "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-cronjobs "kubed" nil t) -;;;###autoload (autoload 'kubed-list-cronjobs "kubed" nil t) -;;;###autoload (autoload 'kubed-create-cronjob "kubed" nil t) -;;;###autoload (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource cronjob - ((schedule ".spec.schedule" 20) - (suspend ".spec.suspend" 20) - (lastschedule ".status.lastScheduleTime" 20) - (lastsuccess ".status.lastSuccessfulTime" 20) - (activejob ".status.active[0].name" 36)) - :create - ((name image schedule &optional context namespace command) - "Schedule IMAGE to run in a cronjob with name NAME according to SCHEDULE. - -Optional argument NAMESPACE is the namespace to use for the cronjob, -defaulting to the current namespace. COMMAND is a list of strings that -represent a program followed by its arguments, if it non-nil then it -overrides the default command IMAGE runs." - (interactive - (let ((name (read-string "Create cronjob with name: ")) - (image nil) - (schedule nil) - (command nil) - (context nil) - (namespace nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create-cronjob)) - (cond - ((string-match "--image=\\(.+\\)" arg) - (setq image (match-string 1 arg))) - ((string-match "--schedule=\\(.+\\)" arg) - (setq schedule (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "-- =\\(.+\\)" arg) - (setq command (split-string-and-unquote (match-string 1 arg)))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (unless image - (setq image (kubed-read-container-image "Image to run"))) - (unless schedule - (setq schedule (read-string "Cron schedule: " "* * * * *"))) - (list name image schedule context namespace command))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "create" "cronjob" name - "--image" image "--schedule" schedule - (append - (when context (list "--context" context)) - (when namespace (list "--namespace" namespace)) - (when command (cons "--" command))))) - (user-error "Failed to create Kubernetes cronjob `%s'" name)) - (message "Created Kubernetes cronjob `%s'." name)) - ;; Commands in *kubed-cronjobs* buffer. - ( toggle-suspension "T" "Toggle suspension of" - (kubed-patch "cronjobs" cronjob - (format - "{\"spec\": {\"suspend\": %s}}" - (if (kubed-cronjob-suspended-p - cronjob kubed-list-context kubed-list-namespace) - "false" "true")) - kubed-list-context kubed-list-namespace)) - ( create-job "j" "Create job from" - (kubed-create-job-from-cronjob - (read-string "Create job with name: ") cronjob - kubed-list-context kubed-list-namespace))) - -;;;###autoload (autoload 'kubed-display-ingressclass "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-ingressclass "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-ingressclasses "kubed" nil t) -;;;###autoload (autoload 'kubed-list-ingressclasss "kubed" nil t) -;;;###autoload (autoload 'kubed-create-ingressclass "kubed" nil t) -;;;###autoload (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource ingressclass - ((controller ".spec.controller" 32) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :namespaced nil - :plural ingressclasses) - -;;;###autoload (autoload 'kubed-display-ingress "kubed" nil t) -;;;###autoload (autoload 'kubed-edit-ingress "kubed" nil t) -;;;###autoload (autoload 'kubed-delete-ingresses "kubed" nil t) -;;;###autoload (autoload 'kubed-list-ingresss "kubed" nil t) -;;;###autoload (autoload 'kubed-create-ingress "kubed" nil t) -;;;###autoload (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap) -(kubed-define-resource ingress - ((class ".spec.ingressClassName" 8) - (creationtimestamp ".metadata.creationTimestamp" 20)) - :plural ingresses - :create - ((name rules &optional context namespace class default-backend annotations) - "Create Kubernetes ingress with name NAME and rules RULES. - -Optional argument NAMESPACE is the namespace to use for the ingress, -defaulting to the current namespace. CLASS is the ingress class, -ANNOTATIONS are a list of annotations for the created ingress, and -DEFAULT-BACKEND is the service to use as a backend for unhandled URLs." - (interactive - (let ((name (read-string "Create ingress with name: ")) - (rules nil) - (context nil) - (namespace nil) - (class nil) - (annotations nil) - (default-backend nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create-ingress)) - (cond - ((string-match "--rule=\\(.+\\)" arg) - (push (match-string 1 arg) rules)) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--class=\\(.+\\)" arg) - (setq class (match-string 1 arg))) - ((string-match "--default-backend=\\(.+\\)" arg) - (setq default-backend (match-string 1 arg))) - ((string-match "--annotation=\\(.+\\)" arg) - (push (match-string 1 arg) annotations)))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (unless rules (setq rules (kubed-read-ingress-rules))) - (list name rules context namespace class default-backend annotations))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "create" "ingress" name - (append - (mapcan (lambda (rule) (list "--rule" rule)) rules) - (when namespace (list "--namespace" namespace)) - (when context (list "--context" context)) - (when class (list "--class" class)) - (when default-backend - (list "--default-backend" default-backend)) - (mapcan (lambda (ann) (list "--annotation" ann)) - annotations)))) - (user-error "Failed to create Kubernetes ingress `%s'" name)) - (message "Created Kubernetes ingress `%s'." name))) - -;; TODO: Events may be numerous. Need to only get a few. -;; ;;;###autoload (autoload 'kubed-list-events "kubed" nil t) -;; ;;;###autoload (autoload 'kubed-event-prefix-map "kubed" nil t 'keymap) -;; (kubed-define-resource event -;; ((last ".lastTimestamp" 20) -;; (type ".type" 10) -;; (reason ".reason" 20) -;; (objectkind ".involvedObject.kind" 12) -;; (objectname ".involvedObject.name" 16) -;; (message ".message" 36))) - -(defun kubed-contexts () - "Return list of Kubernetes contexts." - (process-lines kubed-kubectl-program "config" "get-contexts" "-o" "name")) - -(defun kubed-current-context () - "Return current Kubernetes context." - (car (process-lines kubed-kubectl-program "config" "current-context"))) - -(defun kubed-read-default-namespace-non-empty (context) - "Prompt for a default namespace for CONTEXT, refusing empty input." - (let ((ns (kubed-read-namespace - (format "Default namespace for context `%s'" context) - nil nil context))) - (when (string-empty-p ns) - (user-error "You didn't specify a default namespace")) - ns)) - -(defun kubed-default-context-and-namespace () - "Return default context and namespace as a cons cell (CONTEXT . NAMESPACE)." - (or kubed-default-context-and-namespace - (setq kubed-default-context-and-namespace - (let ((context (kubed-current-context))) - (cons context - (or (kubed-current-namespace context) - (kubed-read-default-namespace-non-empty context))))))) - -(defun kubed-default-context () - "Return default `kubectl' context." - (car (kubed-default-context-and-namespace))) - -(defun kubed-default-namespace () - "Return default Kubernetes namespace in the default context." - (cdr (kubed-default-context-and-namespace))) - -(defun kubed-remote-file-name-p (file-name) - "Check whether FILE-NAME is a Kubed Tramp remote file name." - ;; We use this function to heuristically check file names without - ;; loading `kubed-tramp' (which in turn loads `tramp'). - (string-match-p "[/|]kubedv[0-9]+:" file-name)) - -(defun kubed-local-context () - "Return Kubernetes context local to the current buffer." - (or kubed-list-context - (nth 2 kubed-display-resource-info) - (and (kubed-remote-file-name-p default-directory) - (kubed-tramp-context default-directory)) - (kubed-default-context))) - -(defvar kubed-context-history nil - "History list for `kubed-read-context'.") - -(defun kubed-read-context (prompt &optional default) - "Prompt with PROMPT for a Kubernetes context. - -Optional argument DEFAULT is the minibuffer default argument." - (completing-read (format-prompt prompt default) - (kubed-contexts) - nil 'confirm nil 'kubed-context-history default)) - -;;;###autoload -(defun kubed-use-context (context) - "Set current Kubernetes context to CONTEXT." - (interactive - (list (kubed-read-context "Use context" (kubed-local-context)))) - (unless (zerop - (call-process - kubed-kubectl-program nil nil nil - "config" "use-context" context)) - (user-error "Failed to use Kubernetes context `%s'" context)) - (message "Now using Kubernetes context `%s'." context)) - -;;;###autoload -(defun kubed-rename-context (old new) - "Rename Kubernetes context OLD to NEW." - (interactive - (let ((old (kubed-read-context "Rename context" (kubed-local-context)))) - (list old (read-string (format-prompt "Rename context to" old) - nil 'kubed-context-history old)))) - (unless (zerop - (call-process - kubed-kubectl-program nil nil nil - "config" "rename-context" old new)) - (user-error "Failed to rename Kubernetes context `%s' to `%s'" old new)) - (message "Renamed Kubernetes context `%s' to `%s'." old new)) - -;;;###autoload -(defun kubed-display-config () - "Display current Kubernetes client settings in a YAML buffer." - (interactive) - (let* ((buf (get-buffer-create "*kubed-config*")) - (fun (lambda (&optional _ _) - (let ((inhibit-read-only t) - (target (current-buffer))) - (buffer-disable-undo) - (with-temp-buffer - (unless (zerop - (call-process - kubed-kubectl-program nil t nil "config" "view")) - (error "`kubectl config view' failed")) - (let ((source (current-buffer))) - (with-current-buffer target - (replace-buffer-contents source) - (set-buffer-modified-p nil) - (buffer-enable-undo)))))))) - (with-current-buffer buf - (funcall fun) - (goto-char (point-min)) - (run-hooks 'kubed-yaml-setup-hook) - (setq-local revert-buffer-function fun)) - (display-buffer buf))) - -(defun kubed-current-namespace (&optional context) - "Return current Kubernetes namespace for context CONTEXT. - -If no namespace is configured for CONTEXT, return nil." - (or (car (process-lines - kubed-kubectl-program - "config" "view" "-o" - (format "jsonpath={.contexts[?(.name==\"%s\")].context.namespace}" - (or context (kubed-current-context))))))) - -(defun kubed-local-namespace () - "Return Kubernetes namespace in CONTEXT local to the current buffer." - (or kubed-list-namespace - (nth 3 kubed-display-resource-info) - (and (kubed-remote-file-name-p default-directory) - (kubed-tramp-namespace default-directory)) - (kubed-default-namespace))) - -(defun kubed-local-context-and-namespace () - "Return (CONTEXT . NAMESPACE) pair local to the current buffer." - (or (when-let ((context kubed-list-context)) - (cons context - (or kubed-list-namespace - (kubed-current-namespace context)))) - (when-let ((context (nth 2 kubed-display-resource-info))) - (cons context - (or (nth 3 kubed-display-resource-info) - (kubed-current-namespace context)))) - (when-let ((context (and (kubed-remote-file-name-p default-directory) - (kubed-tramp-context default-directory)))) - (cons context (kubed-tramp-namespace default-directory))) - (kubed-default-context-and-namespace))) - -;;;###autoload -(defun kubed-set-namespace (namespace &optional context) - "Set default Kubernetes namespace in CONTEXT to NAMESPACE. - -Interactively, prompt for NAMESPACE and use the current context. With a -prefix argument, prompt for CONTEXT as well." - (interactive - (let* ((context (kubed-local-context)) - (context (if current-prefix-arg - (kubed-read-context "Context" context) - context))) - (list (kubed-read-namespace "Set namespace" (kubed--namespace context) - nil context) - context))) - (unless (zerop - (call-process - kubed-kubectl-program nil nil nil - "config" "set-context" (or context "--current") - "--namespace" namespace)) - (user-error "Failed to set Kubernetes namespace to `%s'" namespace)) - (message "Default Kubernetes namespace%s is now `%s'." - (if context - (substitute-quotes (concat " for context `" context "'")) - "") - namespace)) - -(defcustom kubed-read-resource-definition-filter-files-by-kind t - "Whether to filter file completion candidates by their Kubernetes \"kind\". - -If this is non-nil, `kubed-read-resource-definition-file-name' only -suggests files with the right \"kind\" as completion candidates when you -call it with non-nil KIND argument. This is useful because you get more -relevant completions, but it may become slow in directories with many -large JSON and YAML files, in which case you can set this option to nil." - :type 'boolean) - -(defun kubed-read-resource-definition-file-name (&optional kind) - "Prompt for Kubernetes resource definition file name. - -Optional argument KIND is the kind of resource the file should define. -If `kubed-read-resource-definition-filter-files-by-kind' is non-nil, -this function suggests only files that define resources of kind KIND as -completion candidates." - (read-file-name - (format "%s definition file: " (or kind "Resource")) nil nil t nil - (if (and kind kubed-read-resource-definition-filter-files-by-kind - (executable-find "grep")) - (let ((cache (make-hash-table :test 'equal))) - (lambda (f) - (or (file-directory-p f) - (when-let ((ext (and (string-match "\\.[^.]*\\'" f) - (substring f (1+ (match-beginning 0)))))) - (or (and (member ext '("yaml" "yml")) - (pcase (gethash (expand-file-name f) cache 'noval) - ('noval - (puthash (expand-file-name f) - (zerop (call-process - "grep" f nil nil "-i" - (format "^kind: %s$" kind))) - cache)) - (val val))) - (and (equal ext "json") - (pcase (gethash (expand-file-name f) cache 'noval) - ('noval - (puthash (expand-file-name f) - (zerop (call-process - "grep" f nil nil "-i" - (format "^kind: %s$" kind))) - cache)) - (val val)))))))) - (lambda (f) - (or (file-directory-p f) - (when (string-match "\\.[^.]*\\'" f) - (member (substring f (1+ (match-beginning 0))) - '("yaml" "yml" "json")))))))) - -;;;###autoload -(defun kubed-apply (config &optional kind context) - "Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT." - (interactive - (let ((config nil) (context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-apply)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--filename=\\(.+\\)" arg) - (setq config (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (unless config - (setq config (kubed-read-resource-definition-file-name))) - (list config nil context))) - (let ((kind (or kind "resource")) - (context (or context (kubed-local-context)))) - (message "Applying Kubernetes %s configuration `%s'..." kind config) - (call-process kubed-kubectl-program nil nil nil - "apply" "-f" (expand-file-name config) "--context" context) - (message "Applying Kubernetes %s configuration `%s'... Done." kind config))) - -;;;###autoload -(defun kubed-create (definition &optional kind context) - "Create resource of kind KIND with definition DEFINITION via CONTEXT." - (interactive - (let ((definition nil) (context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-create)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--filename=\\(.+\\)" arg) - (setq definition (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if current-prefix-arg - (kubed-read-context "Context" cxt) - cxt)))) - (unless definition - (setq definition (kubed-read-resource-definition-file-name))) - (list definition nil context))) - (let ((kind (or kind "resource"))) - (message "Creating Kubernetes %s with definition `%s'..." kind definition) - (message "Creating Kubernetes %s with definition `%s'... Done. New %s name is `%s'." - kind definition kind - (car (apply #'process-lines kubed-kubectl-program - "create" "-f" (expand-file-name definition) - "-o" "jsonpath={.metadata.name}" - (when context (list "--context" context))))))) - -;;;###autoload -(defun kubed-run - ( pod image - &optional context namespace port attach stdin tty rm envs command args) - "Run container IMAGE in a new Kubernetes POD. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context. NAMESPACE is the namespace in which to create POD, -defaulting to the current namespace. PORT is the port to expose, -defaulting to none. If ATTACH is non-nil, then attach to the created -image with a `comint-mode' buffer, and pop to that buffer. Non-nil -STDIN says to keep the standard input of the container open; non-nil TTY -says to allocate a TTY for the container; and non-nil RM says to remove -the container after it exits. ENVS is a list of strings \"VAR=VAL\" -which specify environment variables VAR and values VAL to give them in -the created container. ARGS are command line arguments for the -container command. If COMMAND is non-nil, ARGS consist of a complete -command line, that overrides the container command instead of just -providing it with arguments. - -Interactively, prompt for POD and IMAGE. With a prefix argument, prompt -for NAMESPACE; with a double prefix argument, also prompt for CONTEXT." - (interactive - (let ((pod nil) (image nil) (port nil) (context nil) (namespace nil) - (attach nil) (stdin nil) (tty nil) (rm nil) (envs nil) - (command nil) (args nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-run)) - (cond - ((string-match "--image=\\(.+\\)" arg) - (setq image (match-string 1 arg))) - ((string-match "--port=\\(.+\\)" arg) - (setq port (string-to-number (match-string 1 arg)))) - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((equal "--attach" arg) (setq attach t)) - ((equal "--stdin" arg) (setq stdin t)) - ((equal "--tty" arg) (setq tty t)) - ((equal "--rm" arg) (setq rm t)) - ((equal "--command" arg) (setq command t)) - ((string-match "--env=\\(.+\\)" arg) - (push (match-string 1 arg) envs)) - ((string-match "-- =\\(.+\\)" arg) - (setq args (split-string-and-unquote (match-string 1 arg)))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (setq pod (read-string "Run image in pod with name: ")) - (unless image - (setq image (read-string "Image to run: " nil 'kubed-container-image-history))) - (list pod image context namespace port attach stdin tty rm envs command args))) - (if attach - (pop-to-buffer - (apply #'make-comint "kubed-run" kubed-kubectl-program nil - "run" pod (concat "--image=" image) "--attach" - (append - (mapcar (lambda (env) (concat "--env=" env)) - (cons "TERM=dumb" envs)) - (when namespace (list (concat "--namespace=" namespace))) - (when stdin '("-i")) - (when tty '("-t")) - (when rm '("--rm")) - (when port (list (format "--port=%d" port))) - (when command '("--command")) - (when args (cons "--" args))))) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "run" pod (concat "--image=" image) - (append - (mapcar (lambda (env) (concat "--env=" env)) envs) - (when namespace (list (concat "--namespace=" namespace))) - (when context (list (concat "--context=" context))) - (when stdin '("-i")) - (cond - (attach '("--attach")) - (stdin '("--attach=false"))) - (when tty '("-t")) - (when rm '("--rm")) - (when port (list (format "--port=%d" port))) - (when command '("--command")) - (when args (cons "--" args))))) - (user-error "Failed to run image `%s'" image)) - (message "Image `%s' is now running in pod `%s'." image pod))) - -(defun kubed-pod-containers (pod &optional context namespace) - "Return list of containers in Kubernetes pod POD in NAMESPACE in CONTEXT." - (string-split - (car (apply #'process-lines - kubed-kubectl-program "get" - "pod" pod "-o" "jsonpath={.spec.containers[*].name}" - (append - (when namespace (list "--namespace" namespace)) - (when context (list "--context" context))))) - " ")) - -(defun kubed-pod-default-container (pod &optional context namespace) - "Return default container of Kubernetes pod POD in NAMESPACE in CONTEXT." - (car (apply #'process-lines - kubed-kubectl-program - "get" "pod" pod "-o" - "jsonpath={.metadata.annotations.kubectl\\.kubernetes\\.io/default-container}" - (append - (when namespace (list "--namespace" namespace)) - (when context (list "--context" context)))))) - -(defun kubed-read-container - (pod prompt &optional guess context namespace) - "Prompt with PROMPT for a container in POD and return its name. - -Non-nil optional argument GUESS says to try and guess which container to -use without prompting: if the pod has a -\"kubectl.kubernetes.id/default-container\" annotation, use the -container that this annotation specifes; if there's just one container, -use it; otherwise, fall back to prompting." - (let ((default (kubed-pod-default-container pod context namespace)) - (all 'unset)) - (or - ;; There's a default container, so that's our guess. - (and guess default) - ;; No default, but we're allowed to guess, so check if there's just - ;; one container, and if so that's our guess. - (and guess (setq all (kubed-pod-containers pod context namespace)) - (null (cdr all)) - (car all)) - ;; No guessing, prompt. - (completing-read (format-prompt prompt default) - (completion-table-dynamic - (lambda (_) - (if (eq all 'unset) - (setq all (kubed-pod-containers pod context namespace)) - all))) - nil t nil nil default)))) - -;;;###autoload -(defun kubed-logs - ( type resource &optional context namespace - container follow limit prefix since tail timestamps) - "Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE. - -Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is -the namespace for RESOURCE; CONTAINER is the name of the container in -RESOURCE to show logs for, or t which specifies all relevant containers. - -With a prefix argument, prompt for NAMESPACE; with a double prefix -argument, also prompt for CONTEXT." - (interactive - (let ( type resource context namespace - container follow limit prefix since tail timestamps) - (dolist (arg (kubed-transient-args 'kubed-transient-logs)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--limit-bytes=\\(.+\\)" arg) - (setq limit (string-to-number (match-string 1 arg)))) - ((string-match "--tail=\\(.+\\)" arg) - (setq tail (string-to-number (match-string 1 arg)))) - ((string-match "--since-time=\\(.+\\)" arg) - (setq since (match-string 1 arg))) - ((equal "--all-containers" arg) (setq container t)) - ((equal "--follow" arg) (setq follow t)) - ((equal "--prefix" arg) (setq prefix t)) - ((equal "--timestamps" arg) (setq timestamps t)))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (setq type (kubed-read-resource-type "Type of resource to display" - nil context)) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (setq resource (kubed-read-resource-name type "Show logs for" nil nil - context namespace)) - (list type resource context namespace - (or container - (and (string= type "pods") - (kubed-read-container resource "Container" t - context namespace))) - follow limit prefix since tail timestamps))) - (let* ((context (or context (kubed-local-context))) - (namespace (or namespace (kubed--namespace context))) - (buf (generate-new-buffer - (format "*kubed-logs %s/%s%s in %s[%s]*" - type resource - (cond - ((stringp container) (concat "[" container "]")) - (container "[all containers]") - (t "")) - namespace context)))) - (with-current-buffer buf (run-hooks 'kubed-logs-setup-hook)) - (apply #'start-process "*kubed-logs*" buf - kubed-kubectl-program "logs" (concat type "/" resource) - "--context" context "-n" namespace - (append - (cond - ((stringp container) (list "-c" container)) - (container '("--all-containers"))) - (when follow '("--follow")) - (when prefix '("--prefix")) - (when timestamps '("--timestamps")) - (when since (list "--since-time" since)) - (when tail (list "--tail" (number-to-string tail))) - (when limit (list "--limit-bytes" (number-to-string limit))))) - (display-buffer buf))) - -(defvar kubed-port-forward-process-alist nil - "Alist of current port-forwarding descriptors and corresponding processes.") - -(defun kubed-port-forward-process-alist (&optional _ignored) - "Update and return value of variable `kubed-port-forward-process-alist'." - (setq kubed-port-forward-process-alist - (seq-filter (lambda (pair) - (process-live-p (cdr pair))) - kubed-port-forward-process-alist))) - -;;;###autoload -(defun kubed-forward-port-to-pod - (pod local-port remote-port context namespace) - "Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD." - (interactive - (let* ((c (kubed-local-context)) - (c (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" c) - c)) - (n (kubed--namespace c current-prefix-arg)) - (n (if current-prefix-arg - (kubed-read-namespace "Namespace" n nil c) - n)) - (p (kubed-read-pod "Forward port to pod" nil nil c n)) - (l (read-number "Local port: ")) - (r (read-number "Remote port: "))) - (list p l r c n))) - (message "Forwarding local port %d to remote port %d of pod `%s' in namespace `%s'..." - local-port remote-port pod namespace) - (push - (cons - (format "%s %d:%d in %s[%s]" pod local-port remote-port namespace context) - (apply #'start-process - "*kubed-port-forward*" nil - kubed-kubectl-program "port-forward" - pod (format "%d:%d" local-port remote-port) - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context))))) - kubed-port-forward-process-alist)) - -(defun kubed-stop-port-forward (descriptor) - "Stop Kubernetes port-forwarding with descriptor DESCRIPTOR. - -DESCRIPTOR is a string that says which port-forwarding process to stop, -it has the format \"POD LOCAL-PORT:REMOTE-PORT in NAMESPACE[CONTEXT]\", -where POD is the name of the pod that is the target of the -port-forwarding, LOCAL-PORT is the local port that is being forwarded, -REMOTE-PORT is the correspoding remote port of POD, NAMESPACE is the -namespace of POD and CONTEXT is the `kubectl' context. - -Interactively, prompt for DESCRIPTOR with completion. If there is only -one port-forwarding process, stop that process without prompting." - (interactive - (list - (cond - ((cdr (kubed-port-forward-process-alist)) - (completing-read "Stop port-forwarding: " - (completion-table-dynamic - #'kubed-port-forward-process-alist) - nil t)) - ((caar kubed-port-forward-process-alist)) - (t (user-error "No port-forwarding to Kubernetes in progress"))))) - (if-let ((pair (assoc descriptor kubed-port-forward-process-alist))) - (delete-process (cdr pair)) - (error "No port-forwarding for %s" descriptor)) - (message "Stopped port-forwarding for %s" descriptor)) - -(defvar kubed-container-image-history nil - "Minibuffer history for `kubed-read-container-image'.") - -(defun kubed-read-container-image (prompt &optional default multi) - "Prompt with PROMPT for names of container images. - -Optional argument DEFAULT is the minibuffer default argument. Non-nil -optional argument MULTI says to read multiple image names and return -them as list." - (funcall (if multi #'completing-read-multiple #'completing-read) - (format-prompt prompt default) nil nil nil nil - 'kubed-container-images-history default)) - -(defvar kubed-ingress-rule-history nil - "Minibuffer history for `kubed-read-ingress-rules'.") - -(defun kubed-read-ingress-rules () - "Prompt with PROMPT for Kubernetes ingress rules." - (let ((rules (list (read-string "Ingress rule: " - nil 'kubed-ingress-rule-history)))) - (while (not - (string-empty-p - (car (push (read-string (format-prompt "Additional rules" "done") - nil 'kubed-ingress-rule-history) - rules))))) - (nreverse (cdr rules)))) - -(defvar transient-current-command) - -(defun kubed-transient-args (&optional prefix) - "Return current arguments from transient PREFIX. - -If PREFIX nil, it defaults to the value of `transient-current-command'." - (when-let ((prefix (or prefix (bound-and-true-p transient-current-command)))) - (and (featurep 'kubed-transient) - (fboundp 'transient-args) - (transient-args prefix)))) - -;;;###autoload -(defun kubed-attach (pod &optional container context namespace stdin tty) - "Attach to running process in CONTAINER in Kubernetes POD. - -Optional argument NAMESPACE is the namespace in which to look for POD. -Non-nil STDIN says to connect local standard input to remote process. -Non-nil TTY says to use a TTY for standard input. - -Interactively, prompt for POD; if there are multiple pod containers, -prompt for CONTAINER as well. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. -STDIN and TTY are t interactively." - (interactive - (let ((context nil) (namespace nil) (stdin t) (tty t)) - (dolist (arg (kubed-transient-args 'kubed-transient-attach)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((equal "--stdin" arg) (setq stdin t)) - ((equal "--tty" arg) (setq tty t)))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace)) - (c (kubed-read-container p "Container" t context namespace))) - (list p c context namespace stdin tty)))) - (pop-to-buffer - (apply #'make-comint "kubed-attach" kubed-kubectl-program nil - "attach" pod - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context)) - (when container (list "-c" container)) - (when stdin '("-i")) - (when tty '("-t")))))) - -;;;###autoload -(defun kubed-diff (definition &optional include-managed context) - "Display difference between Kubernetes resource DEFINITION and current state. - -DEFINITION is either a file name or a buffer. Interactively, prompt for -a YAML or JSON file name to use as DEFINITION. - -Optional argument CONTEXT is the `kubectl' context to use, defaulting to -the current context; non-nil INCLUDE-MANAGED (interactively, the prefix -argument) says to include managed fields in the comparison." - (interactive - (let ((definition nil) (context nil) (include-managed nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-diff)) - (cond - ((string-match "--filename=\\(.+\\)" arg) - (setq definition (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((equal "--show-managed-fields" arg) (setq include-managed t)))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (list (or definition (kubed-read-resource-definition-file-name)) - (or include-managed current-prefix-arg) - context))) - (let ((buf (get-buffer-create "*kubed-diff*")) - (args (cons "diff" - (append - (when context (list "--context" context)) - (when include-managed - (list "--show-managed-fields" "true")) - (list "-f" (if (bufferp definition) "-" - (expand-file-name definition))))))) - (with-current-buffer buf - (setq buffer-read-only nil) - (delete-region (point-min) (point-max)) - (fundamental-mode) - (if (bufferp definition) - (with-current-buffer definition - (apply #'call-process-region nil nil kubed-kubectl-program - nil buf nil args)) - (apply #'call-process kubed-kubectl-program - nil t nil args)) - (setq buffer-read-only t) - (diff-mode) - (goto-char (point-min))) - (display-buffer buf))) - -;;;###autoload -(defun kubed-exec - (pod command &optional container context namespace stdin tty args) - "Execute COMMAND with ARGS in CONTAINER in Kubernetes POD. - -Optional argument NAMESPACE is the namespace in which to look for POD. -Non-nil STDIN says to connect local standard input to remote process. -Non-nil TTY says to use a TTY for standard input. - -Interactively, prompt for POD; if there are multiple pod containers, -prompt for CONTAINER as well. With a prefix argument, prompt for -NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. -STDIN and TTY are t interactively." - (interactive - (let ((context nil) (namespace nil) (stdin t) (tty t) (command nil) (args nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-exec)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((equal "--stdin" arg) (setq stdin t)) - ((equal "--tty" arg) (setq tty t)) - ((string-match "-- =\\(.+\\)" arg) - (setq args (split-string-and-unquote (match-string 1 arg)) - command (car args) - args (cdr args))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (unless command - (setq args (split-string-and-unquote - (read-string "Execute command: ")) - command (car args) - args (cdr args))) - (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace)) - (c (kubed-read-container p "Container" t context namespace))) - (list p command c context namespace stdin tty args)))) - (pop-to-buffer - (apply #'make-comint "kubed-exec" kubed-kubectl-program nil - "exec" pod - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context)) - (when container (list "-c" container)) - (when stdin '("-i")) - (when tty '("-t")) - (list "--" command) - args)))) - -(defvar kubed-patch-history nil - "Minibuffer history for `kubed-read-patch'.") - -(defun kubed-read-patch () - "Prompt for a Kubernetes resource patch in JSON or YAML format." - (read-string "Patch (JSON or YAML): " nil 'kubed-patch-history)) - -;;;###autoload -(defun kubed-patch (type name patch &optional context namespace strategy) - "Patch Kubernetes resource NAME of TYPE with patch PATCH. - -Optional argument NAMESPACE is the namespace in which to look for NAME. -STRATEGY is the patch type to use, one of \"json\", \"merge\" and -\"strategic\", defaulting to \"strategic\". - -Interactively, prompt for TYPE, NAME and PATCH. With a prefix argument, -prompt for NAMESPACE too. With a double prefix argument, also prompt -for CONTEXT." - (interactive - (let ((type nil) (context nil) (namespace nil) (strategy nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-patch)) - (cond - ((string-match "--namespace=\\(.+\\)" arg) - (setq namespace (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))) - ((string-match "--type=\\(.+\\)" arg) - (setq strategy (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (unless namespace - (setq namespace (kubed--namespace context current-prefix-arg))) - (list (kubed-read-resource-type "Resource type to patch" nil context) - (kubed-read-resource-name type "Resource to patch" nil nil context namespace) - (kubed-read-patch) context namespace strategy))) - (message "Applying patch to `%s'..." name) - (unless (zerop - (apply #'call-process - kubed-kubectl-program nil nil nil - "patch" type name "-p" patch - (append - (when namespace (list "-n" namespace)) - (when context (list "--context" context)) - (when strategy (list "--type" strategy))))) - (user-error "Patching `%s' failed" name)) - (message "Applying patch to `%s'... Done." name)) - -(defvar kubed--proxy-alist nil - "Alist associating `kubectl' context names and their proxy processes.") - -;;;###autoload -(defun kubed-proxy - (&optional addr port api-prefix www-dir www-prefix context) - "Start a web server on localhost proxying the Kubernetes API server. - -ADDR and PORT are the local address and port to bind the proxy server -to. They default to 127.0.0.1 and 8001, respectively. API-PREFIX is a -prefix under which to proxy the Kubernetes API. WWW-DIR is a local -directory to serve under WWW-PREFIX, which defaults to \"/static/\". -Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the -local context." - (interactive - (let ((addr nil) (port nil) - (api-prefix nil) (www-dir nil) (www-prefix nil) - (context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-proxy)) - (cond - ((string-match "--address=\\(.+\\)" arg) - (setq addr (match-string 1 arg))) - ((string-match "--port=\\(.+\\)" arg) - (setq port (string-to-number (match-string 1 arg)))) - ((string-match "--api-prefix=\\(.+\\)" arg) - (setq api-prefix (match-string 1 arg))) - ((string-match "--www-dir=\\(.+\\)" arg) - (setq www-dir (match-string 1 arg))) - ((string-match "--www-prefix=\\(.+\\)" arg) - (setq www-prefix (match-string 1 arg))) - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (list addr port api-prefix www-dir www-prefix context))) - (let ((context (or context (kubed-local-context)))) - (when-let ((proc (alist-get context kubed--proxy-alist - nil nil #'string=)) - ((process-live-p proc))) - (if (y-or-n-p (concat "Proxy already running for context `" context - "'. Stop it and start new proxy?")) - (kill-process proc) - (user-error "Proxy already running for context `%s'" context)) - (message "Stopped proxy for context `%s'." context)) - (setf (alist-get context kubed--proxy-alist nil nil #'string=) - (apply #'start-process (format "*kubed-proxy[%s]*" context) nil - kubed-kubectl-program "proxy" - "--context" context - (append - (when addr (list "--address" addr)) - (when port (list "--port" (number-to-string port))) - (when api-prefix (list "--api-prefix" api-prefix)) - (when www-dir (list "--www-dir" www-dir)) - (when www-prefix (list "--www-prefix" www-prefix))))) - (message "Started proxy for context `%s'." context))) - -;;;###autoload -(defun kubed-stop-proxy (&optional context) - "Stop local proxy for context CONTEXT, defaulting to the local context." - (interactive - (let ((context nil)) - (dolist (arg (kubed-transient-args 'kubed-transient-proxy)) - (cond - ((string-match "--context=\\(.+\\)" arg) - (setq context (match-string 1 arg))))) - (unless context - (setq context - (let ((cxt (kubed-local-context))) - (if (equal current-prefix-arg '(16)) - (kubed-read-context "Context" cxt) - cxt)))) - (list context))) - (let ((context (or context (kubed-local-context)))) - (if-let ((proc (alist-get context kubed--proxy-alist - nil nil #'string=)) - ((process-live-p proc))) - (kill-process proc) - (user-error "No proxy running for context `%s'" context)) - (message "Stopped proxy for context `%s'." context))) - -(with-eval-after-load 'help-mode - ;; Wait for `help-mode' to define `help-xref'. It's always loaded by - ;; the time we actually need it in `kubed-explain'. - (define-button-type 'kubed-explain - :supertype 'help-xref - 'help-function 'kubed-explain - 'help-echo "mouse-2, RET: explain")) - -(defvar kubed-resource-field-history nil - "Minibuffer history for `kubed-read-resource-field'.") - -(defun kubed-api-resources (&optional context only-namespaced) - "Return list of resource types in the context CONTEXT. - -Non-nil optional argument ONLY-NAMESPACED says to return only namespaced -resource types." - (mapcar - (lambda (line) - (car (split-string line))) - (apply #'process-lines - kubed-kubectl-program - "api-resources" "--no-headers" - (append - (when only-namespaced '("--namespaced=true")) - (when context (list (concat "--context=" context))))))) - -(defun kubed-resource-names (type context &optional namespace) - "Return list of Kubernetes resources of type TYPE in NAMESPACE via CONTEXT." - (unless (kubed--alist type context namespace) - (let ((proc (kubed-update type context namespace))) - (while (process-live-p proc) - (accept-process-output proc 1)))) - (mapcar #'car (alist-get 'resources (kubed--alist type context namespace)))) - -(defun kubed-read-resource-name (type prompt &optional default multi context namespace) - "Prompt with PROMPT for Kubernetes resource name of type TYPE. - -Optional argument DEFAULT is the minibuffer default argument; non-nil -MULTI says to read multiple names and return them as a list; CONTEXT is -the `kubectl' context to use, defaulting to the local context; and -NAMESPACE is the namespace to use, or nil if TYPE is non-namespaced." - (funcall - (if multi #'completing-read-multiple #'completing-read) - (format-prompt prompt default) - (let ((table 'unset)) - (lambda (s p a) - (if (eq a 'metadata) - `(metadata (category . ,(intern (concat "kubernetes-" type)))) - (when (eq table 'unset) - (setq table (kubed-resource-names - type (or context (kubed-local-context)) namespace))) - (complete-with-action a table s p)))) - nil 'confirm nil (intern (concat "kubed-" type "-history")) default)) - -(defun kubed-read-resource-type (prompt &optional default context) - "Prompt with PROMPT for Kubernetes resource type in context CONTEXT. - -Optional argument DEFAULT is the minibuffer default argument." - (completing-read - (format-prompt prompt default) - (kubed-api-resources context) - nil 'confirm nil nil default)) - -(defun kubed-read-resource-field (prompt &optional default context) - "Prompt with PROMPT for Kubernetes resource type or field name. - -Optional argument DEFAULT is the minibuffer default argument, and -CONTEXT is the `kubectl' context to use." - (completing-read - (format-prompt prompt default) - (lambda (s p a) - (unless (eq a 'metadata) - (let ((start 0)) - (while (string-match "\\." s start) - (setq start (match-end 0))) - (if (eq (car-safe a) 'boundaries) - `(boundaries ,start . ,(and (string-match "\\." (cdr a)) - (match-beginning 0))) - (let ((table - (if (zerop start) - ;; Complete resource type. - (kubed-api-resources context) - ;; Complete (sub-)field name. - (with-temp-buffer - (call-process - kubed-kubectl-program nil t nil - "explain" (substring s 0 start)) - (goto-char (point-min)) - (let ((res nil)) - (while (re-search-forward - (rx line-start (+ " ") (group-n 1 (* alnum)) "\t") - nil t) - (push (match-string 1) res)) - res))))) - (if a (complete-with-action a table (substring s start) p) - ;; `try-completion'. - (let ((comp (complete-with-action a table (substring s start) p))) - (if (stringp comp) (concat (substring s 0 start) comp) comp)))))))) - nil 'confirm nil 'kubed-resource-field-history default)) - -;;;###autoload -(defun kubed-explain (field) - "Show help buffer with explanation about Kubernetes resource FIELD." - (interactive - (list (kubed-read-resource-field "Explain type or field"))) - (let ((help-buffer-under-preparation t)) - (help-setup-xref (list #'kubed-explain field) - (called-interactively-p 'interactive)) - (with-help-window (help-buffer) - (with-current-buffer (help-buffer) - (insert (substitute-quotes - (concat "`kubed explain " field "' says:\n\n"))) - (save-excursion - ;; Add button that goes to parent. - (goto-char (point-min)) - (when (re-search-forward (rx " " - (group-n 1 (* graph)) - "." - (+ (not (any ?.))) - line-end) - nil t) - (help-xref-button 1 'kubed-explain (match-string 1)))) - - (call-process kubed-kubectl-program nil t nil "explain" field) - ;; Buttonize references to other fields. - (goto-char (point-min)) - (while (re-search-forward (rx line-start - (+ " ") - (group-n 1 (* alnum)) - "\t") - nil t) - (help-xref-button 1 'kubed-explain - (concat field "." (match-string 1)))))))) - -(defvar kubed-kubectl-command-history nil - "Minibuffer history for `kubed-kubectl-command'.") - -(declare-function cobra-read-command-line "cobra" - (prompt initial &optional hist)) - -(defun kubed-read-kubectl-command (prompt &optional initial) - "Prompt with PROMPT for a `kubectl' command line. - -Optional argument INITIAL added to the initial minibuffer input -following the value of `kubed-kubectl-program' and a space character." - (let ((init (if (consp initial) - (cons (concat kubed-kubectl-program " " (car initial)) - (+ (length kubed-kubectl-program) 1 (cdr initial))) - (concat kubed-kubectl-program " " initial)))) - (cobra-read-command-line prompt init 'kubed-kubectl-command-history))) - -;;;###autoload -(defun kubed-kubectl-command (command) - "Execute `kubectl' COMMAND. - -This function calls `shell-command' (which see) to do the work. - -Interactively, prompt for COMMAND with completion for `kubectl' arguments." - (interactive - (list (kubed-read-kubectl-command - "Command: " - (let* ((args (kubed-transient-args)) - (prefix (and (fboundp 'transient-prefix-object) - (transient-prefix-object))) - (scope (and prefix (fboundp 'eieio-oref) - (eieio-oref prefix 'scope)))) - (when (or args scope) - (concat (string-join (append scope args) " ") " ")))))) - (shell-command command)) - -;;;###autoload (autoload 'kubed-prefix-map "kubed" nil t 'keymap) -(defvar-keymap kubed-prefix-map - :doc "Prefix keymap for Kubed commands." - :prefix 'kubed-prefix-map - "p" 'kubed-pod-prefix-map - "N" 'kubed-namespace-prefix-map - "s" 'kubed-service-prefix-map - "S" 'kubed-secret-prefix-map - "j" 'kubed-job-prefix-map - "d" 'kubed-deployment-prefix-map - "i" 'kubed-ingress-prefix-map - "c" 'kubed-cronjob-prefix-map - "C" #'kubed-use-context - "+" #'kubed-create - "*" #'kubed-apply - "R" #'kubed-run - "=" #'kubed-diff - "E" #'kubed-explain - "P" #'kubed-patch - ":" #'kubed-proxy - "RET" #'kubed-display-resource - "!" #'kubed-kubectl-command) - -(defvar-keymap kubed-menu-map - :doc "Keymap with Kubed menu entries." - :prefix 'kubed-menu-map - "" '("Namespaces..." . kubed-namespace-menu-map) - "" '("Pods..." . kubed-pod-menu-map) - "" '("Persistent Volumes..." . kubed-persistentvolume-menu-map) - "" '("Services..." . kubed-service-menu-map) - "" '("Secrets..." . kubed-secret-menu-map) - "" '("Jobs..." . kubed-job-menu-map) - "" '("Deployments..." . kubed-deployment-menu-map) - "" '("Replica Sets..." . kubed-replicaset-menu-map) - "" '("Daemon Sets..." . kubed-daemonset-menu-map) - "" '("Stateful Sets..." . kubed-statefulset-menu-map) - "" '("Cron Jobs..." . kubed-cronjob-menu-map) - "" '("Ingress Classes..." . kubed-ingressclass-menu-map) - "" '("Ingresses..." . kubed-ingress-menu-map) - "" '("Proxy Kubernetes API" . kubed-proxy) - "" '("Patch Resource" . kubed-patch) - "" '("Diff Config with Live" . kubed-diff) - "" '("Invoke kubectl" . kubed-kubectl-command) - "" '("Explain Type or Field" . kubed-explain) - "" '("Set Current Context" . kubed-use-context) - "" '("Run Image" . kubed-run) - "" '("Apply Config" . kubed-apply) - "" '("Create Resource" . kubed-create) - "" '("Display Resource" . kubed-display-resource)) - -;;;###autoload -(define-minor-mode kubed-menu-bar-mode - "Add \"Kubernetes\" menu to your menu bar." - :global t - (if kubed-menu-bar-mode - (keymap-set-after (current-global-map) - " " '("Kubernetes" . kubed-menu-map)) - (keymap-global-unset " "))) - -(defvar reporter-prompt-for-summary-p) - -(defun kubed-submit-bug-report () - "Report a Kubed issue to the maintainers via email." - (interactive) - (require 'reporter) - (let ((reporter-prompt-for-summary-p t)) - (reporter-submit-bug-report - "Kubed Development <~eshel/kubed-devel@lists.sr.ht>" - (format "Kubed") - '(kubed-kubectl-program) - nil nil - (propertize " " - 'display - (propertize - "Insert your bug report below. -If possible, specify where you got Emacs, kubectl and Kubed, -and include a recipe for reproducing your issue. -[This line and the above text are not included in your report.]" - 'face 'italic))))) - -(provide 'kubed) -;;; kubed.el ends here diff --git a/elpa/kubed-0.5.0/kubed.info b/elpa/kubed-0.5.0/kubed.info deleted file mode 100644 index afd891ea..00000000 Binary files a/elpa/kubed-0.5.0/kubed.info and /dev/null differ diff --git a/elpa/kubed-0.5.0/kubed.texi b/elpa/kubed-0.5.0/kubed.texi deleted file mode 100644 index 86e6e1c1..00000000 --- a/elpa/kubed-0.5.0/kubed.texi +++ /dev/null @@ -1,817 +0,0 @@ -\input texinfo @c -*- texinfo -*- -@c %**start of header -@setfilename kubed.info -@settitle Kubed: Kubernetes, Emacs, done! -@documentencoding UTF-8 -@documentlanguage en -@set MAINTAINERSITE @uref{https://eshelyaron.com,maintainer webpage} -@set MAINTAINER Eshel Yaron -@set MAINTAINEREMAIL @email{me@eshelyaron.com} -@set MAINTAINERCONTACT @uref{mailto:me@eshelyaron.com,contact the maintainer} -@c %**end of header - -@copying -This manual is for Kubed 0.5.0, a rich Emacs interface for Kubernetes. - -Copyright @copyright{} 2024-2025 Eshel Yaron. - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -@end quotation -@end copying - -@dircategory Emacs -@direntry -* Kubed: (kubed). Kubernetes, Emacs, done! -@end direntry - -@finalout -@titlepage -@title Kubed: Kubernetes, Emacs, done! -@author Eshel Yaron (@email{me@@eshelyaron.com}) -@end titlepage - -@contents - -@ifnottex -@node Top -@top Kubed: Kubernetes, Emacs, done! - -This manual is for Kubed 0.5.0, a rich Emacs interface for Kubernetes. - -@end ifnottex - -@menu -* Overview:: Introduction to Kubed -* Getting Started:: First steps with Kubed -* Usage:: Using Kubed to interact with Kubernetes -* Extending Kubed:: Adding support for your custom resources -* Contributing:: Get involved in Kubed development -* Indices:: -@end menu - -@node Overview -@chapter Overview - -@cindex Kubed -@cindex kubed -Kubed is a rich Kubernetes interface within Emacs. It helps you work -with your Kubernetes clusters and deployments with the full power of -@command{kubectl}, and with the comfort and confidence of an intuitive -interactive interface. - -@float -@ifset split -@image{../../assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png} -@end ifset -@ifclear split -@image{assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png} -@end ifclear -@caption{Pods, logs, shells, YAMLs, all in one integrated interface} -@end float - -You can use Kubed to: - -@itemize -@item -Browse and manage Kubernetes workloads -@item -Connect to pods and edit files or execute commands -@item -Create new resources, edit and delete them -@item -Work with multiple clusters -@item -Get help about various Kubernetes objects -@item -@dots{} -@end itemize - -These features and others are documented in the rest of this manual, -along with many options that Kubed provides for you to customize its -behavior. - -@node Getting Started -@chapter Getting Started - -@cindex installation - -Get Kubed from GNU ELPA with @kbd{M-x package-install}, or use your -favorite Emacs package manager to install Kubed from Git. You can -clone the Kubed Git repository from any of the following locations: - -@itemize -@item -@url{https://git.sr.ht/~eshel/kubed} -@item -@url{https://github.com/eshelyaron/kubed.git} -@item -@url{git://git.eshelyaron.com/kubed.git} -@end itemize - -@cindex requirements -To get started with Kubed, all you need is @command{kubectl} and Emacs. - -Kubed tries to find @command{kubectl} in the directories listed in the -Emacs variable @code{exec-path}. When Emacs is started from a shell, it -initializes @code{exec-path} from the shell's @env{PATH} environment -variable which normally includes the location of @command{kubectl} in -common @command{kubectl} installations. If Emacs doesn't find the -@command{kubectl} executable via @code{exec-path}, you can tell Kubed -where to find it by customizing @code{kubed-kubectl-program}. - -@defopt kubed-kubectl-program -Name of @command{kubectl} executable file to use. -@end defopt - -@node Usage -@chapter Usage - -Kubed comes with a large number of Emacs command for interacting with -Kubernetes. Some commands perform one action on one resource, while -others show you a menu with many resources and let you interact with any -number of them. Some commands are specific to one type of resources, -while others act on resources of any type. There are different ways to -use Kubed, depending on your use case. - -The two most important entry points for Kubed are -@code{kubed-prefix-map} and @code{kubed-transient}: - -@anchor{Definition of kubed-prefix-map} -@cindex global prefix keymap -@cindex prefix keymap, global commands -@cindex keymap, for global commands -@defvr Keymap kubed-prefix-map -Keymap with bindings for many useful Kubed commands. -@end defvr - -The prefix keymap @code{kubed-prefix-map} gives you quick access to the -main Kubed commands. You may want to bind it to a convenient key in -your global keymap, for example: - -@lisp -(keymap-global-set "C-c k" 'kubed-prefix-map) -@end lisp - -With this binding in place, you can create a new Kubernetes resource -with @kbd{C-c k +} and attach to a running pod with @kbd{C-c k p a}. -The @kbd{C-c k} binding is just a suggestion of course, feel free to -pick any key sequence you like. - -@float - -@ifset split -@image{../../assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png} -@end ifset -@ifclear split -@image{assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png} -@end ifclear - -@ifset split -@image{../../assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png} -@end ifset -@ifclear split -@image{assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png} -@end ifclear - -@caption{Use @code{kubed-prefix-map} for quick access to the main Kubed commands} -@end float - -You can also access all of the commands in @code{kubed-prefix-map} via -the menu-bar @samp{Kubernetes} menu---to add this menu to your -menu-bar, enable the global minor mode @code{kubed-menu-bar-mode}: - -@anchor{Definition of kubed-menu-bar-mode} -@deffn {Minor Mode} kubed-menu-bar-mode -Add @samp{Kubernetes} menu to your menu bar. -@end deffn - -The other important entry point that Kubed provides for exploring and -performing different Kubernetes operations is @code{kubed-transient}: - -@deffn Command kubed-transient -Open the main Kubed transient menu. -@end deffn - -This command pops up the Kubed transient menu, which gives you -interactive guidance for invoking Kubed commands. -@xref{Top,,,transient}. - -The following sections describe in detail the various Kubed commands. - -@menu -* Display Resource:: -* Browse Resources:: -* Context and Namespace:: -* Transient Menus:: -* Scale Deployment:: -@end menu - -@node Display Resource -@section Display Resource - -You can view the YAML description of any resource in your Kubernetes -cluster. In Kubed, this is referred to as @dfn{displaying} the given -resource. The following commands display a Kubernetes resource: - -@deffn Command kubed-display-resource -Display a Kubernetes resource. -@end deffn - -@deffn Command kubed-display-pod -@deffnx Command kubed-display-deployment -@deffnx Command kubed-display-namespace -@deffnx Command kubed-display-@var{foo} -Display Kubernetes resource of a given type. -@end deffn - -Command @code{kubed-display-resource} can display any Kubernetes -resource. It prompts you to select a resource type and a resource -name, and displays that resource in a dedicated buffer. By default, -this command assumes you want to display a resource that is in the -current namespace, but if you invoke @code{kubed-display-resource} -with a prefix argument (@kbd{C-u}) and choose a namespaced resource -type, then it also lets you select the namespace of the resource. -With a double prefix argument, it lets you select which -@command{kubectl} context to use too. @xref{Context and Namespace}. - -If you have @code{kubed-prefix-map} bound to @kbd{C-c k}, you can -invoke @code{kubed-display-resource} with @kbd{C-c k @key{RET}}. This -command is also available from the menu-bar ``Kubernetes'' menu -(@pxref{Definition of kubed-menu-bar-mode}), and from the transient -``Kubernetes Display'' menu (@pxref{Transient Menus}). - -You can also display the resource at point in resources list buffers -by simply typing @kbd{@key{RET}}. @xref{Browse Resources}. - -Kubed also provides a dedicated @code{kubed-display-@var{foo}} command -for each supported resource type @var{foo}. These commands are just -like @code{kubed-display-resource}, except that they do not prompt you -for a type, since they are type-specific. For example, -@code{kubed-display-pod} only prompts you for a pod name, and then -displays it like @code{kubed-display-resource} does. - -You can invoke these commands by adding a type-specific key before -@kbd{@key{RET}} in @kbd{C-c k @key{RET}}: @kbd{C-c k p @key{RET}} -invokes @code{kubed-display-pod}, @kbd{C-c k d @key{RET}} invokes -@code{kubed-display-deployment}, and so on. - -When Kubed prepares a buffer for displaying a resource, it runs the -hook @code{kubed-yaml-setup-hook} right after populating the buffer -with the YAML description of the resource: - -@defopt kubed-yaml-setup-hook -List of functions to call, in order, to prepare YAML buffers. The -first function on this hook is normally the major mode you want to use -for YAML buffers that display Kubernetes resources. By default, this -is the list @code{(yaml-ts-mode view-mode)}. -@end defopt - -In addition, Kubed enables a bespoke minor mode -@code{kubed-display-resource-mode} in buffers that display Kubernetes -resources: - -@deffn {Minor Mode} kubed-display-resource-mode -Minor mode for buffers that display a Kubernetes resource. -@end deffn - -@noindent -This minor mode does the following: - -@itemize -@item -It shows the word @samp{Kubed} in the mode line, so you know you're -seeing a rendered Kubernetes resource, rather than any old YAML file. -@item -It allows you to @emph{bookmark} the resource your viewing and your -position in its YAML description with the regular Emacs bookmarks -commands (@pxref{Bookmarks,,,emacs}), namely @kbd{C-x r m}. -@item -@kindex C-c C-j -@findex kubed-display-resource-jump-to-list -It binds the key sequence @kbd{C-c C-j} to command -@code{kubed-display-resource-jump-to-list}, which pops up the -resources list buffer for the type of the displayed resource, and -takes you to the line corresponding to it. -@item -@kindex C-c C-c -@findex kubed-display-resource-replace -@kindex C-c C-= -@findex kubed-display-resource-diff -@kindex C-x C-q -@findex read-only-mode -It binds @kbd{C-c C-c} to command -@code{kubed-display-resource-replace}, which lets you apply any -changes that you make in the YAML buffer back to the resource. When -you hit @kbd{C-c C-c}, Kubed asks you for confirmation before -proceeding; you can reply with @kbd{d} (@samp{diff}) to show a diff -between the current state of the resource and the current buffer -contents. You can also display this diff anytime with @kbd{C-c C-=}. -Note that by default Kubed displays resources in read-only buffers, so -you may need to hit @kbd{C-x C-q} (@code{read-only-mode}) before -making changes in the buffer. -@item -@kindex C-x x g -@findex revert-buffer -@findex revert-buffer-quick -It lets you repopulate the buffer with updated information about the -resource with @kbd{C-x x g} (@code{revert-buffer-quick}) and -@w{@kbd{M-x revert-buffer}}. This is also useful if you edit the -resource and want to restart from a clean slate. -@end itemize - -@float -@ifset split -@image{../../assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png} -@end ifset -@ifclear split -@image{assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png} -@end ifclear -@caption{Type @kbd{C-x C-q} in a resource YAML buffer to edit it, @kbd{C-c C-c} to apply} -@end float - -@node Browse Resources -@section Browse Resources - -Kubed gives you an interactive list of resources for each type, that -you access with the @code{kubed-list-@var{resource}s} commands, such -as @code{kubed-list-pods}. - -These commands are bound to @kbd{l} in Kubed's type-specific prefix -keymaps, most of which are accessible via the global -@code{kubed-prefix-map} by default (@pxref{Definition of -kubed-prefix-map}). So if you've bound @code{kubed-prefix-map} to -@kbd{C-c k}, you can pop up the pods list with @kbd{C-c k p l}, the -deployments list with @kbd{C-c k d l}, the jobs list with @w{@kbd{C-c -k j l}}, etc. Normally, Kubed shows the list of resources in the -current namespace, but if you invoke these commands with a prefix -argument (say, @kbd{C-u C-c k p l}), they first prompt you to select a -namespace, and then show resources in the namespace you selected. - -The list of @var{resource}s in shown a buffer called @w{@file{*Kubed -@var{resource}s@@@var{namespace}[@var{context}]*}}, where -@var{context} is a @command{kubectl} context, and @var{namespace} is a -namespace in @var{context}. For example, Kubed shows the list of pods -in namespace @samp{default} for context @samp{minikube} in buffer -@file{*Kubed pos@@default[minikube]}. For non-namespaced resources, -the @w{@samp{@@@var{namespace}}} part is omitted. - -Each resource type has its own major mode for list buffers with -type-specific commands and operations, but they are all also derived -from a shared parent mode. The pods list uses the -@code{kubed-pods-mode} (@samp{Kubernetes Pods}) major mode, the list -of Kubernetes deployments uses @code{kubed-deployments-mode}, and so -on. - -@float -@ifset split -@image{../../assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png} -@end ifset -@ifclear split -@image{assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png} -@end ifclear -@caption{Browse your pods, deployments, and other resources with Kubed list buffers} -@end float - -The common parent major mode is @code{kubed-list-mode}: - -@deffn {Major Mode} kubed-list-mode -Major mode for listing generic Kubernetes resources. -@end deffn - -This mode provides the following commands for all type-specific -derived modes: - -@table @kbd -@kindex @key{?} -@findex kubed-list-transient -@item @key{?} -Show help in transient menu (@code{kubed-list-transient}). -@kindex @key{RET} -@findex kubed-list-select-resource -@item @key{RET} -Display the resource at point in the current window -(@code{kubed-list-select-resource}). -@kindex o -@findex kubed-list-select-resource-other-window -@item o -Display the resource at point in another window and select that window -(@code{kubed-list-select-resource-other-window}). -@kindex C-o -@findex kubed-list-display-resource -@item C-o -Display the resource at point in another window without selecting it -(@code{kubed-list-display-resource}). -@kindex D -@findex kubed-list-delete -@item D -Delete the resource at point (@code{kubed-list-delete}). -@kindex e -@findex kubed-list-edit -@item e -Edit the resource at point (@code{kubed-list-edit}). -@kindex P -@findex kubed-list-patch -@item P -Patch the resource at point (@code{kubed-list-patch}). -@kindex g -@findex kubed-list-update -@item g -Update the resources list by fetching new information from Kubernetes -(@code{kubed-list-update}). -@kindex / -@findex kubed-list-set-filter -@item / -Filter the current list of resources (@code{kubed-list-set-filter}). -@xref{List Filter}. -@kindex d -@findex kubed-list-mark-for-deletion -@item d -Mark the resource at point for deletion -(@code{kubed-list-mark-for-deletion}). Resources marked for deletion -have a @samp{D} in the beginning of their line. -@kindex x -@findex kubed-list-delete-marked -@item x -Delete marked resources (@code{kubed-list-delete-marked}). -@kindex u -@findex kubed-list-unmark -@item u -Unmark from resource at point (@code{kubed-list-unmark}). -@kindex w -@findex kubed-list-copy-as-kill -@item w -Copy name of resource at point into the kill ring -(@code{kubed-list-copy-as-kill}). -@kindex n -@findex next-line -@item n -Move point to the next line (@code{next-line}). -@kindex p -@findex previous-line -@item p -Move point to the previous line (@code{previous-line}). -@kindex @key{TAB} -@findex kubed-list-next-column -@item @key{TAB} -Move point to the next column. If point is already at the last -column, move to the first column of the next line instead -(@code{kubed-list-next-column}). -@kindex S-@key{TAB} -@findex kubed-list-previous-column -@item S-@key{TAB} -Move point to the previous column. If point is already at the first -column, move to the last column of the previous line instead -(@code{kubed-list-previous-column}). -@kindex S -@findex tabulated-list-sort -@item S -Sort lines by the column at point (@code{tabulated-list-sort}). -@kindex | -@findex kubed-list-fit-column-width-to-content -@item | -Fit width of column at point to its content -(@code{kubed-list-fit-column-width-to-content}). With non-negative -prefix argument @var{n} (for example, @kbd{0 |}), fit @var{n}th -column. With negative prefix argument (@kbd{- |}), fit all columns. -@kindex @{ -@findex tabulated-list-narrow-current-column -@item @{ -Narrow the column at point -(@code{tabulated-list-narrow-current-column}). -@kindex @} -@findex tabulated-list-widen-current-column -@item @} -Widen the column at point -(@code{tabulated-list-widen-current-column}). -@end table - -In addition, you can bookmark any Kubed resources list buffer with the -usual @kbd{C-x r m}. @xref{Bookmarks,,,emacs}. - -Note that @code{kubed-list-mode} (and its type-specific derivatives) -bind the @kbd{g} key, which is commonly bound to @code{revert-buffer}, -to @code{kubed-list-update}. The difference between these commands is -that @code{revert-buffer} only refreshes the list display, without -fetching updated data from Kubernetes. You can still invoke -@code{revert-buffer} with @kbd{C-x x g} or @kbd{M-x}, if you need it. - -@vindex kubed-list-mode-line-format -Whenever Kubed is fetching data from Kubernetes to update a resources -list buffer, the mode line of that list buffer shows the @samp{[...]} -indicator. You can set user option @code{kubed-list-mode-line-format} -to customize this indicator. - -@menu -* List Filter:: -@end menu - -@node List Filter -@subsection Filtering Resource Lists - -In all Kubernetes resource list buffers, you can use @kbd{/} -(@code{kubed-list-set-filter}) to @dfn{filter} the list of resources. -This command sets the filter of the current buffer, which specifies -conditions on resources (lines). Resources that don't satisfy the -conditions are hidden, so you can focus on those that do. - -Filters can be simple (@dfn{atomic filters}) or complex (@dfn{composed -filters}). In the simple case, you enter a filter in the minibuffer -in the format @w{@samp{@var{op} @var{col} @var{val}}}, where @var{op} -is a comparison operator, one of @samp{=}, @samp{~}, @samp{<} and -@samp{>}; @var{col} is a column name; and @var{val} is a value to -compare to values of @var{col} with @var{op}. - -If @var{op} is @samp{=}, it says to keep only lines whose @var{col} -equals @var{val}. If @var{op} is @samp{~}, it says to keep lines -whose @var{col} matches the @var{val} as a regular expression. -@samp{<} and @samp{>} compare column values to numeric values. For -example, the filter @samp{= Name foobar} keeps only resources whose -name is @samp{foobar}. To include whitespace in @var{val}, wrap -@var{val} in double quotes: @samp{= Name "foo bar"}. - -The possible values of @var{op} and their meanings are defined in -@code{kubed-list-filter-operator-alist}, which is a user option you -can use to add or change the meaning of filter operators: - -@defopt kubed-list-filter-operator-alist -Association list of filter operators and corresponding Emacs Lisp -functions. See the documentation string of this option for specifics. -@end defopt - -You can use more refined filters by composing simple filters. To add -another filter that resources must satisfy, wrap your two filters in -parentheses and put them next to each other: - -@lisp -(= Name foobar) (~ Namespace kube) -@end lisp - -@noindent -This filter keeps only resources whose name is @samp{foobar} in -namespaces that include @samp{kube} as a substring, it expresses the -conjunction of the two simple filters. - -To negate a simple filter, put a single quote ahead of it, like so: - -@lisp -(= Name foobar) '(~ Namespace kube) -@end lisp - -@noindent -This matches resources named @samp{foobar} in namespaces that do -@emph{not} contain @samp{kube}. - -To specify a disjunction of simple filters (and negated simple -filters), add another level of nesting: - -@lisp -((= Name spam) (= Name foobar)) '(~ Namespace kube) -@end lisp - -@noindent -This filter matches resources named either @samp{spam} or -@samp{foobar}, in namespaces that do not contain @samp{kube}. - -While entering a filter in the minibuffer, @kbd{@key{TAB}} completion -is available for column names and values. To clear the filter, just -exit the minibuffer with an empty input. - -@node Context and Namespace -@section Context and Namespace - -Kubed uses @command{kubectl} to interact with Kubernetes clusters, and -you can use multiple @command{kubectl} @dfn{contexts} in Kubed to work -with different Kubernetes clusters in parallel. Within each context, -Kubed lets you work in multiple @dfn{namespaces} too. In general, -each buffer has its own @dfn{local context} and @dfn{local namespace}, -and Kubed commands use these local context and namespace by default. -This is similar to how different buffers have different values of -@code{default-directory} (@pxref{File Names,,,emacs}), and how that -affects commands that interact with the filesystem. - -For Kubed buffers that display a Kubernetes resource (@pxref{Display -Resource}) or a list of resources (@pxref{Browse Resources}), the -buffer-local context and namespace are the context and namespace of -the resources the buffer displays. For non-Kubed buffers, the user -option @code{kubed-default-context-and-namespace} determines the -default local context and namespace. - -@defopt kubed-default-context-and-namespace -Default @command{kubectl} context and Kubernetes namespace for Kubed -commands. The value of this option is either a cons cell -@w{@code{(@var{context} . @var{namespace})}} or @code{nil}. If it is -@code{nil}, Kubed initializes this option to a cons cell with the -current @command{kubectl} context and namespace for that context on -the first time Kubed consults this option. -@end defopt - -As mentioned above, most Kubed commands use the local context and -namespace by default---it is also conventional for Kubed commands to -let you choose a different namespace if you invoke them with a prefix -argument (@kbd{C-u}), and to also let you choose a different context -if you invoke them with a double prefix argument (@kbd{C-u C-u}). - -The following functions return the local context and namespace for -buffer in which you call them: - -@defun kubed-local-context -Return the local @command{kubectl} context for the current buffer. -@end defun - -@defun kubed-local-namespace -Return the local Kubernetes namespace for the current buffer. -@end defun - -@defun kubed-local-context-and-namespace -Return the local context and namespace for the current buffer as a -cons cell @w{@code{(@var{context} . @var{namespace})}}. -@end defun - -@node Transient Menus -@section Transient Menus - -Kubed provides a set of keyboard-driven @dfn{transient menus} -(@pxref{Top,,,transient}) that you can use to explore and invoke -various commands. Transient menus show you available commands along -with their key bindings, which helps you use many different commands -without the need to remember the key bindings for all them. -Additionally, the transient menus allow you to specify options and -switches for the commands you invoke, which may not be available when -invoking these commands directly. For example, while you can invoke -command @code{kubed-logs} directly to view logs from a container -running in Kubernetes, the ``Kubernetes Logs'' transient menu which -you open with @code{kubed-transient-logs} lets you set a maximum -number of logs to retrieve, among other knobs and handles. - -@float - -@ifset split -@image{../../assets/kubed-transient,,,Image: The Kubed main transient menu,.png} -@end ifset -@ifclear split -@image{assets/kubed-transient,,,Image: The Kubed main transient menu,.png} -@end ifclear - -@ifset split -@image{../../assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png} -@end ifset -@ifclear split -@image{assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png} -@end ifclear - -@caption{Explore Kubed commands with transient menus} -@end float - -Command @code{kubed-transient} opens the Kubed ``root'' transient -menu, which is a dispatch that lets you access different transient -menus, such as the aforementioned ``Kubernetes Logs'' transient menu. -It's a good idea to bind @code{kubed-transient} to a convenient key, -either in the global keymap or under @code{kubed-prefix-map}: - -@lisp -(keymap-global-set "s-k" #'kubed-transient) -(keymap-set kubed-prefix-map "k" #'kubed-transient) -@end lisp - -In Kubed resource list buffers, type @kbd{?} to pop up a transient -menu with commands that are specific to the type of resources the -buffer displays. @xref{Browse Resources}. - -@node Scale Deployment -@section Scale Deployment - -You can use Kubed to @dfn{scale} Kubernetes a deployment, which means -setting the size of the deployment in terms of the number of replicas -it governs. - -@deffn Command kubed-scale-deployment -Scale a Kubernetes deployment. -@end deffn - -@code{kubed-scale-deployment} is bound to @kbd{$} in the -@code{kubed-deployment-prefix-map}, so if you have -@code{kubed-prefix-map} bound to @kbd{C-c k} then you can invoke it -with @kbd{C-c k d $}. @xref{Definition of kubed-prefix-map}. This -command prompts you for a deployment and then lets you select a new -number of replicas for that deployment. By default you are prompted -for deployment in the local context and namespace (@pxref{Context and -Namespace}); with a prefix argument, you can specify a different -namespace; with a double prefix argument (@kbd{C-u C-u}), you can -specify a different context too. - -In the deployments list buffer, you can scale the deployment at point -by simply typing @kbd{$}. @xref{Browse Resources}. - -@float -@ifset split -@image{../../assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png} -@end ifset -@ifclear split -@image{assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png} -@end ifclear -@caption{Scale deployments with @kbd{$} in the deployments list buffer} -@end float - -Lastly, you can scale deployments using the transient menu -@code{kubed-transient-scale-deployment}, which is available from the -main Kubed transient by pressing @kbd{$}. @xref{Transient Menus}. - -@node Extending Kubed -@chapter Extending Kubed - -Kubed has built-in support for many common types of Kubernetes -resources. ``Support'' for a resource type in Kubed just means -providing common commands for working with resources of that type, -such as a command for showing the interactive list of these resources, -like @code{kubed-list-pods} for Kubernetes pods. In Kubed, the macro -@code{kubed-define-resource} is used to define these common commands -and add support for more resource types: - -@deffn Macro kubed-define-resource resource &optional properties &rest [ keyword argument ]@dots{} commands -Define commands for @var{resource}. -@end deffn - -Say you want to add support for your Kubernetes service accounts. -With @code{kubed-define-resource}, all you need to do is to add the -following line to your Emacs initialization file: - -@lisp -(kubed-define-resource serviceaccount) -@end lisp - -This line defines the following commands for you: - -@itemize -@item -@code{kubed-display-serviceaccount} -@item -@code{kubed-list-serviceaccounts} -@item -@code{kubed-edit-serviceaccount} -@item -@code{kubed-delete-serviceaccount} -@item -@code{kubed-create-serviceaccount} -@item -@code{kubed-explain-serviceaccounts} -@end itemize - -See the documentation string of @code{kubed-define-resource} -(@w{@kbd{C-h f}}) for details about the optional arguments of this -macro: the @var{properties} argument which lets you specify what Kubed -should show in the resource list buffer and the @code{commands} argument -which lets you associate additional commands with your resource type. - -@node Contributing -@chapter Contributing - -We highly appreciate all contributions, including bug reports, -patches, improvement suggestions, and general feedback! - -The best way to get in touch with the Kubed maintainers is via -@uref{https://lists.sr.ht/~eshel/kubed-devel, the Kubed mailing list}. - -@deffn Command kubed-submit-bug-report -Report a bug in Kubed to the maintainers via mail. -@end deffn - -You can use the command @kbd{M-x kubed-submit-bug-report} to easily -contact the Kubed maintainers from within Emacs. This command opens a -new buffer with a message template ready to be sent to the development -mailing list. - -@node Indices -@unnumbered Indices - -@menu -* Function Index:: -* Variable Index:: -* Keystroke Index:: -* Concept Index:: -@end menu - -@node Function Index -@unnumberedsec Function index - -@printindex fn - -@node Variable Index -@unnumberedsec Variable index - -@printindex vr - -@node Keystroke Index -@unnumberedsec Keystroke index - -@printindex ky - -@node Concept Index -@unnumberedsec Concept index - -@printindex cp - -@bye diff --git a/elpa/kubed-0.6.1.signed b/elpa/kubed-0.6.1.signed new file mode 100644 index 00000000..cff056aa --- /dev/null +++ b/elpa/kubed-0.6.1.signed @@ -0,0 +1 @@ +Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) (trust undefined) created at 2026-04-14T11:05:02+0200 using EDDSA \ No newline at end of file diff --git a/elpa/kubed-0.6.1/.elpaignore b/elpa/kubed-0.6.1/.elpaignore new file mode 100644 index 00000000..afa5a63e --- /dev/null +++ b/elpa/kubed-0.6.1/.elpaignore @@ -0,0 +1,5 @@ +.dir-locals.el +README.md +kubed.png +explain-and-patch.png +pod-context-menu.png diff --git a/elpa/kubed-0.6.1/LICENSE b/elpa/kubed-0.6.1/LICENSE new file mode 100644 index 00000000..9934a864 --- /dev/null +++ b/elpa/kubed-0.6.1/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024-2026 Eshel Yaron + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/elpa/kubed-0.6.1/NEWS.org b/elpa/kubed-0.6.1/NEWS.org new file mode 100644 index 00000000..d23a42ff --- /dev/null +++ b/elpa/kubed-0.6.1/NEWS.org @@ -0,0 +1,235 @@ +#+title: Kubed NEWS -- history of user-visible changes +#+author: Eshel Yaron +#+email: me@eshelyaron.com +#+language: en +#+options: ':t toc:nil num:nil ^:{} + +This file contains the release notes for Kubed, a rich Emacs interface +for Kubernetes. + +For further details, see the Kubed manual: +[[https://eshelyaron.com/kubed.html][https://eshelyaron.com/kubed.html]]. + +* Version 0.6.1 on 2026-04-13 + +This is a maintenance release, it includes one important bug fix: + +** Fix "Invalid format string" error in Tramp integration + +This version fixes a regression introduced in version 0.6.0, which +caused an error when starting a shell or opening Dired inside a pod. + +See bug report at https://lists.sr.ht/~eshel/kubed-devel/%3C87zf36vqaa.fsf@gmail.com%3E + +* Version 0.6.0 on 2026-04-11 + +** Kubed now uses the remote ~kubectl~ on remote hosts + +When you invoke Kubed commands in a buffer whose ~default-directory~ +points to a directory on a remote host (such as +=/ssh:user@example.com:/some/remote/dir/=), Kubed runs ~kubectl~ on +the remote host, so you can interact with clusters that are configured +in the remote kubeconfig and accessible from the remote host. + +Note that this is a rather extensive change, please tell us about +issues/regressions if you see any! + +** ~kubed-kubectl-program~ is now connection-local + +You can configure different ~kubed-kubectl-program~ values for +different hosts on which you run ~kubectl~ via Kubed commands, by +giving the variable a connection-local value for certain hosts. +For example: + +#+begin_src emacs-lisp +(connection-local-set-profile-variables + 'my-kubed-profile-for-somehost + '((kubed-kubectl-program . "/home/user/my-kubectl"))) + +(connection-local-set-profiles + '(:application kubed :machine "somehost.com") + 'my-kubed-profile-for-somehost) +#+end_src + +** New user option ~kubed-default-context-and-namespace-alist~ + +This user option generalizes and supersedes the existing user option +~kubed-default-context-and-namespace~, which is considered obsolete +but is still available. The new user option lets you set different +defaults depending on the host on which Kubed is running ~kubectl~. + +** Command ~kubed-transient~ is now bound to ~k~ in ~kubed-prefix-map~ + +This was already a recommended binding for this command, which opens +the "root" Kubed transient menu. + +** New user option ~kubed-logs-follow~ + +The new user option ~kubed-logs-follow~ controls whether Kubed follows +new log entries by default when showing Kubernetes logs. +It defaults to ~t~. + +** New user option ~kubed-logs-tail-lines~ + +Kubed commands that show logs for Kubernetes resources now fetch only +the most recent 128 log lines by default, to avoid flooding the logs +buffer with the full history of long-running workloads. You can +customize this limit with the new user option ~kubed-logs-tail-lines~; +set it to 0 to fetch all available log lines. + +** Command ~kubed-logs~ is now bound to ~L~ in ~kubed-prefix-map~ + +* Version 0.5.1 on 2026-02-13 + +** Fix error with minibuffer completion for custom Kubernetes resources + +** ~kubed-use-context~ now also updates ~kubed-default-context-and-namespace~ + +Setting the default ~kubectl~ context with ~kubed-use-context~ now +also updates the user option ~kubed-default-context-and-namespace~, +such that Kubed commands will also use the new context as a default. + +* Version 0.5.0 on 2025-06-11 + +** DaemonSets support + +Kubed now provides commands for working with DaemonSets by default. +Remember that you can always configure support for additional resource +types with the ~kubed-define-resource~ macro! + +** Fix Tramp integration for context names with non-alphanumeric characters + +This version fixes an issue in the Kubed integration with Tramp, which +caused it to fail for ~kubectl~ contexts whose name includes ":" and +most other non-alphanumeric characters. + +See bug report at https://lists.sr.ht/~eshel/kubed-devel/%3C87ldqz70a6.fsf@gmail.com%3E + +* Version 0.4.3 on 2025-01-21 + +This is a maintenance release, it includes minor improvements and one +important bug fix: + +** Fix 'kubed-list-delete-marked' in non-default context + +Marking resources with ~d~ and deleting them with ~x~ now works also +in resource tables of resources in non-default contexts or namespaces. + +* Version 0.4.2 on 2024-10-22 + +** New user option 'kubed-list-mode-line-format' + +This user option lets you customize the indicator that Kubed shows in +the mode line of resource table buffers when update is in progress. + +** Fix Tramp method autoload issue + +This version arranges for the Kubed Tramp integration to be loaded +earlier, which circumvents the "Method ‘kubedv1’ is not known" error +that some users have experienced. + +* Version 0.4.1 on 2024-09-23 + +** New command and transient menu for scaling deployments + +You can now scale Kubernetes deployment with Kubed, directly with +~kubed-scale-deployment~, from the deployments table buffer, or via +the new transient menu ~kubed-transient-scale-deployment~. + +** New commands and transient menu for managing Kubernetes API proxies + +You can now use Kubed to create proxy servers that give access to the +Kubernetes API server. The commands ~kubed-proxy~ and +~kubed-stop-proxy~ start and stop proxy servers, respectively. The +new transient menu ~kubed-transient-proxy~ lets specify options when +starting a proxy, such as the local port to use. + +* Version 0.4.0 on 2024-08-23 + +** ~kubed-list-update~ is now bound to ~g~ in resource table buffers. + +Previously, this command was bound to the slightly less convenient +capital ~G~. This shadows the default binding of ~revert-buffer~, +which you can still invoke via ~C-x x g~. + +** Introduce resource type specific bindings in resource table help transients. + +The help transient menu that you get with ~?~ in resource table +buffers now includes type-specific bindings, such as the ~F~ key for +forwarding a local port to a pod in the Kubed pods buffer. + +** New transient menu ~kubed-transient-logs~ for showing container logs. + +** Improved Tramp integration. + +Kubed now uses a bespoke Tramp method to open Dired and Shell buffers +inside Kubernetes pods. The main advantage of this method is the +ability to work with multiple ~kubectl~ contexts simultaneously. This +method requires Tramp 2.7 or later, Kubed will complain if you try to +start remote Dired or Shell with an earlier Tramp version. + +* Version 0.3.2 on 2024-08-15 + +** Improved support for multiple contexts and namespaces + +Each buffer now has a local context and namespace, which acts as the +default/current context and namespace when you invoke Kubed commands +from that buffer. See new manual section "Context and Namespace" for +more details. + +** New filter operators ~<~ and ~>~ in resource tables. + +These operators let you filter line with columns that are less than or +greater than a given value. + +** New command for applying changes to displayed resource. + +You can now edit displayed resource YAML buffers after you select a +resource with ~RET~ in the table buffer, and apply your changes to the +live resource with ~C-c C-c~. + +* Version 0.3.1 on 2024-08-06 + +** New command for fitting column width to content in resource tables. + +** New transient menu showing help in resource table buffers. + +* Version 0.3.0 on 2024-08-05 + +** New command for copying name of resource at point to kill ring. + +** New commands for running ~kubectl~ command on resource at point. + +** Support bookmarking resource list and resource details buffers. + +** New command for jumping from resource details buffer to list buffer. + +** Fix installation on Doom Emacs. + +** New transient menu for displaying resources. + +** Support multiple resource list buffers with different namespaces or contexts. + +* Version 0.2.0 on 2024-08-02 + +** Ensure compatibility with Emacs 29. + +** Add right-click context menus in resource tables. + +** New menu-bar "Kubernetes" menu. + +** New commands for restarting and watching deployments. + +** Add filtering capability to all resource tables. + +** New cron job commands: suspend, resume, and start job now. + +** New commands for patching resources. + +** New useful columns in services table and deployments table. + +** Use multi-column layout in transient menus. + +* Version 0.1.0 on 2024-07-28 + +Initial release. diff --git a/elpa/kubed-0.6.1/README-elpa b/elpa/kubed-0.6.1/README-elpa new file mode 100644 index 00000000..2dc11028 --- /dev/null +++ b/elpa/kubed-0.6.1/README-elpa @@ -0,0 +1,34 @@ +This library defines commands for interacting with Kubernetes +resources, such as Kubernetes pods, services, deployments, and more. + +Use `kubed-display-pod' to display a Kubernetes pod, +`kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and +`kubed-list-pods' to see a menu of all pods. You can create new pods +from YAML or JSON files with `kubed-create-pod'. + +Similar commands are defined for other types of resources as well. + +This library interacts with Kubernetes via `kubectl', and uses the +current `kubectl' context and namespace by default. To change your +current context or namespace, use commands `kubed-use-context' and +`kubed-set-namespace' respectively; you can also interact with +resources in other namespaces without changing your default +namespace, for example you can call `kubed-list-pods' with a prefix +argument to choose another namespace for listing pods. The prefix +keymap `kubed-prefix-map' gives you quick access to these and other +useful commands, you may want to bind it globally to a convenient key +with `keymap-global-set': + + (keymap-global-set "C-c k" 'kubed-prefix-map) + +In addition, the command `kubed-transient' lets you explore various +Kubernetes operations with a transient menu interface. You may also +want to enable `kubed-menu-bar-mode', which add a "Kubernetes" menu +to your menu-bar with many useful entries. + +If you want to work with more or different types of Kubernetes +resources, use the macro `kubed-define-resource'. This macro defines +some common functions and commands that'll get you started with ease. + +For more information, see the Kubed manual at (info "(kubed)Top"), or +online at https://eshelyaron.com/kubed.html \ No newline at end of file diff --git a/elpa/kubed-0.6.1/assets/kubed-deployment-prefix-map.png b/elpa/kubed-0.6.1/assets/kubed-deployment-prefix-map.png new file mode 100644 index 00000000..19551b12 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-deployment-prefix-map.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-list-transient.png b/elpa/kubed-0.6.1/assets/kubed-list-transient.png new file mode 100644 index 00000000..c0fdb281 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-list-transient.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-overview.png b/elpa/kubed-0.6.1/assets/kubed-overview.png new file mode 100644 index 00000000..b74db912 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-overview.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-prefix-map.png b/elpa/kubed-0.6.1/assets/kubed-prefix-map.png new file mode 100644 index 00000000..0f0d6090 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-prefix-map.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-replace-diff.png b/elpa/kubed-0.6.1/assets/kubed-replace-diff.png new file mode 100644 index 00000000..6e6d07a1 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-replace-diff.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-scale-deployments.png b/elpa/kubed-0.6.1/assets/kubed-scale-deployments.png new file mode 100644 index 00000000..3f51ecd3 Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-scale-deployments.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-transient-exec.png b/elpa/kubed-0.6.1/assets/kubed-transient-exec.png new file mode 100644 index 00000000..5f412e8e Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-transient-exec.png differ diff --git a/elpa/kubed-0.6.1/assets/kubed-transient.png b/elpa/kubed-0.6.1/assets/kubed-transient.png new file mode 100644 index 00000000..97fa375f Binary files /dev/null and b/elpa/kubed-0.6.1/assets/kubed-transient.png differ diff --git a/elpa/kubed-0.6.1/cobra.el b/elpa/kubed-0.6.1/cobra.el new file mode 100644 index 00000000..e9f63dfe --- /dev/null +++ b/elpa/kubed-0.6.1/cobra.el @@ -0,0 +1,143 @@ +;;; cobra.el --- Complete Cobra command lines -*- lexical-binding: t; -*- + +;; Copyright (C) 2024-2026 Free Software Foundation, Inc. + +;; Author: Eshel Yaron +;; Keywords: tools + +;;; Commentary: + +;; Cobra is a popular Golang framework for CLI programs. This library +;; defines function `cobra-read-command-line', which helps you read a +;; command line for a program that uses Cobra, with completion. +;; Prominent examples of Cobra programs are `kubectl' and `docker'. + +;;; Code: + +(defvar cobra--cache nil) + +(defun cobra-completion-table (executable s p a) + "Completion table for command lines that invoke EXECUTABLE. + +Perform completion action A on string S with predicate P." + (let ((start 0)) + (while (string-match "[[:space:]=]" s start) + (setq start (match-end 0))) + (if (eq a 'metadata) + `(metadata + (category . cobra-command-line) + (affixation-function + . ,(lambda (cands) + (let ((max (seq-max + (cons 0 (mapcar #'string-width cands))))) + (mapcar + (lambda (cand) + (list + cand "" + (if-let + ((desc (get-text-property + 0 'cobra-argument-description + cand))) + (concat + (make-string (1+ (- max (string-width cand))) ?\s) + (propertize desc 'face 'completions-annotations)) + ""))) + cands))))) + (let* ((lines + (cdr + (if (string= s (car cobra--cache)) + ;; Cache hit. + cobra--cache + (setq + cobra--cache + (cons s + (apply #'process-lines-ignore-status + executable "__complete" + (let ((args (cdr (split-string-and-unquote s)))) + (if (string-suffix-p " " s) + ;; Restore omitted empty argument. + (nconc args '("")) + args)))))))) + (code nil) + (comps (seq-take-while + (lambda (line) + (not (and (string-match "^:\\([0-9]+\\)$" line) + (setq code (string-to-number + (match-string 1 line)))))) + lines))) + ;; `code' encodes "completion directives", as follows: + ;; #b000001: An error occurred, ignore completions. + ;; #b000010: Don't add space after completion. (TODO.) + ;; #b000100: Don't fall back to file completion. + ;; #b001000: Completions are really file extension filters. + ;; #b010000: Complete directory names. + ;; #b100000: Preserve completions order. + (when (and code (zerop (logand 1 code))) + ;; Error bit in unset, proceed. + (if (= #b100 (logand #b100 code)) + ;; No file name completion. + (if (eq (car-safe a) 'boundaries) + `(boundaries + ,start . ,(and (string-match "[[:space:]=]" (cdr a)) + (match-beginning 0))) + (let ((table + (mapcar + ;; Annotate completion candidates. + (lambda (comp) + (pcase (split-string comp "\t" t) + (`(,c ,d . ,_) + (propertize + c 'cobra-argument-description + ;; Only keep first sentence. + (car (split-string d "\\." t)))) + (`(,c . ,_) c))) + comps))) + (if a (complete-with-action a table (substring s start) p) + ;; `try-completion'. + (let ((comp (complete-with-action a table (substring s start) p))) + (if (stringp comp) (concat (substring s 0 start) comp) comp))))) + ;; File name completion. + (setq p + (cond + ((= #b1000 (logand #b1000 code)) + ;; `comps' are valid extensions. + (lambda (f) + (or (file-directory-p f) + (when (string-match "\\.[^.]*\\'" f) + (member (substring f (1+ (match-beginning 0))) + comps))))) + ((= #b10000 (logand #b10000 code)) + ;; Directory name completion. + #'file-directory-p))) + (if (eq (car-safe a) 'boundaries) + ;; Find nested boundaries. + (let* ((suf (cdr a)) + (bounds (completion-boundaries + (substring s start) #'completion-file-name-table p + (substring suf 0 (string-match "[[:space:]=]" suf))))) + `(boundaries ,(+ (car bounds) start) . ,(cdr bounds))) + (if a (complete-with-action a #'completion-file-name-table + (substring s start) p) + (let ((comp (complete-with-action a #'completion-file-name-table + (substring s start) p))) + (if (stringp comp) (concat (substring s 0 start) comp) comp)))))))))) + +;;;###autoload +(defun cobra-read-command-line (prompt initial &optional hist) + "Prompt with PROMPT for a command line starting with INITIAL. + +Optional argument HIST is the name of the history list variable to use, +if it is nil or omitted, it defaults to `shell-command-history'." + (let ((exec (car (split-string-and-unquote (car (ensure-list initial)))))) + (minibuffer-with-setup-hook + (:append (lambda () + (let ((map (make-sparse-keymap))) + ;; Ensure SPC is self-inserting. + (keymap-unset map "SPC") + (use-local-map + (make-composed-keymap map (current-local-map)))))) + (completing-read prompt (apply-partially #'cobra-completion-table exec) + nil nil initial (or hist 'shell-command-history))))) + +(provide 'cobra) +;;; cobra.el ends here diff --git a/elpa/kubed-0.6.1/dir b/elpa/kubed-0.6.1/dir new file mode 100644 index 00000000..c2a31044 --- /dev/null +++ b/elpa/kubed-0.6.1/dir @@ -0,0 +1,18 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "H" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Kubed: (kubed). Kubernetes, Emacs, done! diff --git a/elpa/kubed-0.6.1/kubed-autoloads.el b/elpa/kubed-0.6.1/kubed-autoloads.el new file mode 100644 index 00000000..861ae2e8 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed-autoloads.el @@ -0,0 +1,517 @@ +;;; kubed-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from cobra.el + +(autoload 'cobra-read-command-line "cobra" +"Prompt with PROMPT for a command line starting with INITIAL. + +Optional argument HIST is the name of the history list variable to use, +if it is nil or omitted, it defaults to `shell-command-history'. + +(fn PROMPT INITIAL &optional HIST)") +(register-definition-prefixes "cobra" '("cobra-")) + + +;;; Generated autoloads from kubed.el + +(autoload 'kubed-display-resource "kubed" +"Display Kubernetes RESOURCE of type TYPE in CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCE. With a prefix argument \\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well. + +(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t) +(autoload 'kubed-display-resource-handle-bookmark "kubed" +"Display Kubernetes resource according to BOOKMARK. + +(fn BOOKMARK)") +(autoload 'kubed-list-handle-bookmark "kubed" +"Display Kubernetes resource according to BOOKMARK. + +(fn BOOKMARK)") +(autoload 'kubed-delete-resources "kubed" +"Delete Kubernetes RESOURCES of type TYPE in context CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCES. With a prefix argument \\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well. + +(fn TYPE RESOURCES CONTEXT &optional NAMESPACE)" t) +(autoload 'kubed-edit-resource "kubed" +"Edit Kubernetes RESOURCE of type TYPE in context CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCES. With a prefix argument \\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well. + +(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t) +(autoload 'kubed-define-resource "kubed" +"Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS. + +RESOURCE is a symbol corresponding to a Kubernetes resource type, such +as `pod' or `service'. This macro defines the following commands for +interacting with Kubernetes RESOURCEs: + +- `kubed-display-RESOURCE': prompt for a RESOURCE and display its + description in YAML format. See also `kubed-yaml-setup-hook'. +- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it. +- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it. +- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the + current namespace. The RESOURCEs list buffer uses a dedicated major + mode, `kubed-RESOURCEs-mode', which is also defined by this macro. +- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file. +- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs. + +This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map', +with bindings for the above commands. + +PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS) +that specify properties of RESOURCEs. PROP is the name of the property, +as a symbol; JSON-PATH is a JSONPath expression that evaluates to the +value of PROP when applied to the JSON representation of a RESOURCE. +WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted. WIDTH is +used as the default width of the column corresponding to PROP in +RESOURCEs list buffers; SORT is sort predicate, a function that takes +two values of PROP as strings and returns non-nil if the first should +sort before the second; FORMAT is a function that takes a value of PROP +and formats it. If you provide a FORMAT function and a SORT function, +then the SORT function gets the formatted values (the output of the +FORMAT function), not the original values. If you want to sort based on +the unformatted original values, you can store them as text properties +in your FORMAT function and access them in your SORT function. + +ATTRS is a plist of additional attributes of the PROP column, see +`tabulated-list-format' for available attributes. + +For example, if PROPERTIES is (phase \".status.phase\" 10) that means +that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose +values are typically 10 columns wide. The first property in PROPERTIES +is used to annotate completion candidates when prompting for a RESOURCE. + +COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that +define commands for RESOURCE list buffers. COMMAND is a symbol +specifying the suffix of the command name, the full name of the command +is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is +either a string that specifies a key sequence to bind to the command in +`kubed-RESOURCEs-mode-map', or nil if the command should not be bound; +DOC-PREFIX is a string used to construct the docstring of the command, +this macro appends the string \" Kubernetes RESOURCE at point.\" to it +to obtain the final docstring; lastly, BODY is the body the command. +Within BODY, the variable RESOURCE is let-bound to the name of the +RESOURCE at point. For example, if RESOURCE is `pod', the following +COMMANDS element defines a command `kubed-pods-frob' and binds it to the +key \"f\" in `kubed-pods-mode-map': + + (frob \"f\" \"Frobnicate\" + (message \"Preparing...\") + (frobnicate-pod pod) + (message \"Done.\")) + +By default, this macro assumes that RESOURCE is namespaced. To define a +namespaceless resource type, put `:namespaced nil' before COMMANDS: + + (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil + CMD1 + CMD2 + ...) + +Other keyword arguments that go between PROPERTIES and COMMANDS are: + +- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the + resource creation command, `kubed-create-RESOURCE'. ARGLIST, + DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'. +- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the + prefix keymap `kubed-RESOURCE-prefix-map' and the + `kubed-RESOURCE-menu-map' menu. Each element (KEY LABEL DEFINITION) + says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to + add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL. +- `:plural PLURAL': specify plural form of RESOURCE, as a symbol. If + you omit this keyword argument, the plural form defaults to RESOURCE + followed by \"s\". +- `:logs t': generate `kubed-logs-for-RESOURCE' command. +- `:suffixes (SUFFIX...)': add type-specific transient suffixes to + `kubed-list-transient'. + +(fn RESOURCE &optional PROPERTIES &rest COMMANDS)" nil t) + (autoload 'kubed-display-pod "kubed" nil t) + (autoload 'kubed-edit-pod "kubed" nil t) + (autoload 'kubed-delete-pods "kubed" nil t) + (autoload 'kubed-list-pods "kubed" nil t) + (autoload 'kubed-create-pod "kubed" nil t) + (autoload 'kubed-logs-for-pod "kubed" nil t) + (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-namespace "kubed" nil t) + (autoload 'kubed-edit-namespace "kubed" nil t) + (autoload 'kubed-delete-namespaces "kubed" nil t) + (autoload 'kubed-list-namespaces "kubed" nil t) + (autoload 'kubed-create-namespace "kubed" nil t) + (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-persistentvolume "kubed" nil t) + (autoload 'kubed-edit-persistentvolume "kubed" nil t) + (autoload 'kubed-delete-persistentvolumes "kubed" nil t) + (autoload 'kubed-list-persistentvolumes "kubed" nil t) + (autoload 'kubed-create-persistentvolume "kubed" nil t) + (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-service "kubed" nil t) + (autoload 'kubed-edit-service "kubed" nil t) + (autoload 'kubed-delete-services "kubed" nil t) + (autoload 'kubed-list-services "kubed" nil t) + (autoload 'kubed-create-service "kubed" nil t) + (autoload 'kubed-logs-for-service "kubed" nil t) + (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-secret "kubed" nil t) + (autoload 'kubed-edit-secret "kubed" nil t) + (autoload 'kubed-delete-secrets "kubed" nil t) + (autoload 'kubed-list-secrets "kubed" nil t) + (autoload 'kubed-create-secret "kubed" nil t) + (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-job "kubed" nil t) + (autoload 'kubed-edit-job "kubed" nil t) + (autoload 'kubed-delete-jobs "kubed" nil t) + (autoload 'kubed-list-jobs "kubed" nil t) + (autoload 'kubed-create-job "kubed" nil t) + (autoload 'kubed-logs-for-job "kubed" nil t) + (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap) +(autoload 'kubed-watch-deployment-status "kubed" +"Show and update status of Kubernetes deployment DEP in a dedicate buffer. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. CB is an optional callback function to call with +no arguments when the deployment ends. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. + +(fn DEP &optional CONTEXT NAMESPACE CB)" t) +(autoload 'kubed-scale-deployment "kubed" +"Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. + +(fn DEP REPS &optional CONTEXT NAMESPACE)" t) +(autoload 'kubed-restart-deployment "kubed" +"Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. CB is an optional callback function to call with +no arguments when the deployment ends. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. + +(fn DEP &optional CONTEXT NAMESPACE)" t) + (autoload 'kubed-display-deployment "kubed" nil t) + (autoload 'kubed-edit-deployment "kubed" nil t) + (autoload 'kubed-delete-deployments "kubed" nil t) + (autoload 'kubed-list-deployments "kubed" nil t) + (autoload 'kubed-create-deployment "kubed" nil t) + (autoload 'kubed-logs-for-deployment "kubed" nil t) + (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-replicaset "kubed" nil t) + (autoload 'kubed-edit-replicaset "kubed" nil t) + (autoload 'kubed-delete-replicasets "kubed" nil t) + (autoload 'kubed-list-replicasets "kubed" nil t) + (autoload 'kubed-create-replicaset "kubed" nil t) + (autoload 'kubed-logs-for-replicaset "kubed" nil t) + (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-daemonset "kubed" nil t) + (autoload 'kubed-edit-daemonset "kubed" nil t) + (autoload 'kubed-delete-daemonsets "kubed" nil t) + (autoload 'kubed-list-daemonsets "kubed" nil t) + (autoload 'kubed-create-daemonset "kubed" nil t) + (autoload 'kubed-logs-for-daemonset "kubed" nil t) + (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-statefulset "kubed" nil t) + (autoload 'kubed-edit-statefulset "kubed" nil t) + (autoload 'kubed-delete-statefulsets "kubed" nil t) + (autoload 'kubed-list-statefulsets "kubed" nil t) + (autoload 'kubed-create-statefulset "kubed" nil t) + (autoload 'kubed-logs-for-statefulset "kubed" nil t) + (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-cronjob "kubed" nil t) + (autoload 'kubed-edit-cronjob "kubed" nil t) + (autoload 'kubed-delete-cronjobs "kubed" nil t) + (autoload 'kubed-list-cronjobs "kubed" nil t) + (autoload 'kubed-create-cronjob "kubed" nil t) + (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-ingressclass "kubed" nil t) + (autoload 'kubed-edit-ingressclass "kubed" nil t) + (autoload 'kubed-delete-ingressclasses "kubed" nil t) + (autoload 'kubed-list-ingressclasss "kubed" nil t) + (autoload 'kubed-create-ingressclass "kubed" nil t) + (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap) + (autoload 'kubed-display-ingress "kubed" nil t) + (autoload 'kubed-edit-ingress "kubed" nil t) + (autoload 'kubed-delete-ingresses "kubed" nil t) + (autoload 'kubed-list-ingresss "kubed" nil t) + (autoload 'kubed-create-ingress "kubed" nil t) + (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap) +(autoload 'kubed-use-context "kubed" +"Set default `kubectl' context to CONTEXT. + +This command sets the global `kubectl' default context, and updates the +value of `kubed-default-context-and-namespace-alist' accordingly. + +Interactively, prompt for CONTEXT with completion. + +(fn CONTEXT)" t) +(autoload 'kubed-rename-context "kubed" +"Rename Kubernetes context OLD to NEW. + +(fn OLD NEW)" t) +(autoload 'kubed-display-config "kubed" +"Display current Kubernetes client settings in a YAML buffer." t) +(autoload 'kubed-set-namespace "kubed" +"Set default Kubernetes namespace in CONTEXT to NAMESPACE. + +If CONTEXT is the current default context, also update the value of user +option `kubed-default-context-and-namespace-alist' to use NAMESPACE as +the default namespace. + +Interactively, prompt for NAMESPACE and use the current context. With a +prefix argument, prompt for CONTEXT as well. + +(fn NAMESPACE &optional CONTEXT)" t) +(autoload 'kubed-apply "kubed" +"Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT. + +(fn CONFIG &optional KIND CONTEXT)" t) +(autoload 'kubed-create "kubed" +"Create resource of kind KIND with definition DEFINITION via CONTEXT. + +(fn DEFINITION &optional KIND CONTEXT)" t) +(autoload 'kubed-run "kubed" +"Run container IMAGE in a new Kubernetes POD. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context. NAMESPACE is the namespace in which to create POD, +defaulting to the current namespace. PORT is the port to expose, +defaulting to none. If ATTACH is non-nil, then attach to the created +image with a `comint-mode' buffer, and pop to that buffer. Non-nil +STDIN says to keep the standard input of the container open; non-nil TTY +says to allocate a TTY for the container; and non-nil RM says to remove +the container after it exits. ENVS is a list of strings \"VAR=VAL\" +which specify environment variables VAR and values VAL to give them in +the created container. ARGS are command line arguments for the +container command. If COMMAND is non-nil, ARGS consist of a complete +command line, that overrides the container command instead of just +providing it with arguments. + +Interactively, prompt for POD and IMAGE. With a prefix argument, prompt +for NAMESPACE; with a double prefix argument, also prompt for CONTEXT. + +(fn POD IMAGE &optional CONTEXT NAMESPACE PORT ATTACH STDIN TTY RM ENVS COMMAND ARGS)" t) +(autoload 'kubed-logs "kubed" +"Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE. + +Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is +the namespace for RESOURCE; CONTAINER is the name of the container in +RESOURCE to show logs for, or t which specifies all relevant containers. + +With a prefix argument, prompt for NAMESPACE; with a double prefix +argument, also prompt for CONTEXT. + +(fn TYPE RESOURCE &optional CONTEXT NAMESPACE CONTAINER FOLLOW LIMIT PREFIX SINCE TAIL TIMESTAMPS)" t) +(autoload 'kubed-forward-port-to-pod "kubed" +"Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD. + +(fn POD LOCAL-PORT REMOTE-PORT CONTEXT NAMESPACE)" t) +(autoload 'kubed-attach "kubed" +"Attach to running process in CONTAINER in Kubernetes POD. + +Optional argument NAMESPACE is the namespace in which to look for POD. +Non-nil STDIN says to connect local standard input to remote process. +Non-nil TTY says to use a TTY for standard input. + +Interactively, prompt for POD; if there are multiple pod containers, +prompt for CONTAINER as well. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. +STDIN and TTY are t interactively. + +(fn POD &optional CONTAINER CONTEXT NAMESPACE STDIN TTY)" t) +(autoload 'kubed-diff "kubed" +"Display difference between Kubernetes resource DEFINITION and current state. + +DEFINITION is either a file name or a buffer. Interactively, prompt for +a YAML or JSON file name to use as DEFINITION. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; non-nil INCLUDE-MANAGED (interactively, the prefix +argument) says to include managed fields in the comparison. + +(fn DEFINITION &optional INCLUDE-MANAGED CONTEXT)" t) +(autoload 'kubed-exec "kubed" +"Execute COMMAND with ARGS in CONTAINER in Kubernetes POD. + +Optional argument NAMESPACE is the namespace in which to look for POD. +Non-nil STDIN says to connect local standard input to remote process. +Non-nil TTY says to use a TTY for standard input. + +Interactively, prompt for POD; if there are multiple pod containers, +prompt for CONTAINER as well. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. +STDIN and TTY are t interactively. + +(fn POD COMMAND &optional CONTAINER CONTEXT NAMESPACE STDIN TTY ARGS)" t) +(autoload 'kubed-patch "kubed" +"Patch Kubernetes resource NAME of TYPE with patch PATCH. + +Optional argument NAMESPACE is the namespace in which to look for NAME. +STRATEGY is the patch type to use, one of \"json\", \"merge\" and +\"strategic\", defaulting to \"strategic\". + +Interactively, prompt for TYPE, NAME and PATCH. With a prefix argument, +prompt for NAMESPACE too. With a double prefix argument, also prompt +for CONTEXT. + +(fn TYPE NAME PATCH &optional CONTEXT NAMESPACE STRATEGY)" t) +(autoload 'kubed-proxy "kubed" +"Start a web server on localhost proxying the Kubernetes API server. + +ADDR and PORT are the local address and port to bind the proxy server +to. They default to 127.0.0.1 and 8001, respectively. API-PREFIX is a +prefix under which to proxy the Kubernetes API. WWW-DIR is a local +directory to serve under WWW-PREFIX, which defaults to \"/static/\". +Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the +local context. + +(fn &optional ADDR PORT API-PREFIX WWW-DIR WWW-PREFIX CONTEXT)" t) +(autoload 'kubed-stop-proxy "kubed" +"Stop local proxy for context CONTEXT, defaulting to the local context. + +(fn &optional CONTEXT)" t) +(autoload 'kubed-explain "kubed" +"Show help buffer with explanation about Kubernetes resource FIELD. + +(fn FIELD)" t) +(autoload 'kubed-kubectl-command "kubed" +"Execute `kubectl' COMMAND. + +This function calls `shell-command' (which see) to do the work. + +Interactively, prompt for COMMAND with completion for `kubectl' arguments. + +(fn COMMAND)" t) + (autoload 'kubed-prefix-map "kubed" nil t 'keymap) +(defvar kubed-menu-bar-mode nil +"Non-nil if Kubed-Menu-Bar mode is enabled. +See the `kubed-menu-bar-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `kubed-menu-bar-mode'.") +(custom-autoload 'kubed-menu-bar-mode "kubed" nil) +(autoload 'kubed-menu-bar-mode "kubed" +"Add \"Kubernetes\" menu to your menu bar. + +This is a global minor mode. If called interactively, toggle the +`Kubed-Menu-Bar mode' mode. If the prefix argument is positive, enable +the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable the +mode if ARG is nil, omitted, or is a positive number. Disable the mode +if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='kubed-menu-bar-mode)'. + +The mode's hook is called both when the mode is enabled and when it is +disabled. + +(fn &optional ARG)" t) +(register-definition-prefixes "kubed" '("kubed-")) + + +;;; Generated autoloads from kubed-common.el + +(register-definition-prefixes "kubed-common" '("kubed-")) + + +;;; Generated autoloads from kubed-tramp.el + +(autoload 'kubed-tramp-context "kubed-tramp" +"Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME. + +(fn FILE-NAME)") +(autoload 'kubed-tramp-namespace "kubed-tramp" +"Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME. + +(fn FILE-NAME)") +(autoload 'kubed-tramp-assert-support "kubed-tramp" +"Check if Kubed Tramp support is available, throw `user-error' if not.") +(autoload 'kubed-tramp-enable "kubed-tramp" +"Enable Kubed integration with Tramp.") + (with-eval-after-load 'tramp (kubed-tramp-enable)) +(register-definition-prefixes "kubed-tramp" '("kubed-tramp-")) + + +;;; Generated autoloads from kubed-transient.el + + (autoload 'kubed-transient "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t) + (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t) + (autoload 'kubed-transient-logs "kubed-transient" nil t) + (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t) + (autoload 'kubed-transient-proxy "kubed-transient" nil t) + (autoload 'kubed-transient-rollout "kubed-transient" nil t) + (autoload 'kubed-transient-attach "kubed-transient" nil t) + (autoload 'kubed-transient-diff "kubed-transient" nil t) + (autoload 'kubed-transient-exec "kubed-transient" nil t) + (autoload 'kubed-transient-run "kubed-transient" nil t) + (autoload 'kubed-transient-apply "kubed-transient" nil t) + (autoload 'kubed-transient-patch "kubed-transient" nil t) + (autoload 'kubed-transient-create "kubed-transient" nil t) + (autoload 'kubed-transient-display "kubed-transient" nil t) + (autoload 'kubed-transient-edit "kubed-transient" nil t) + (autoload 'kubed-transient-delete "kubed-transient" nil t) + (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t) + (autoload 'kubed-transient-create-ingress "kubed-transient" nil t) + (autoload 'kubed-transient-create-deployment "kubed-transient" nil t) + (autoload 'kubed-transient-create-job "kubed-transient" nil t) + (autoload 'kubed-list-transient "kubed-transient" nil t) +(register-definition-prefixes "kubed-transient" '("kubed-transient-")) + +;;; End of scraped data + +(provide 'kubed-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; kubed-autoloads.el ends here diff --git a/elpa/kubed-0.6.1/kubed-common.el b/elpa/kubed-0.6.1/kubed-common.el new file mode 100644 index 00000000..e5199bf0 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed-common.el @@ -0,0 +1,25 @@ +;;; kubed-common.el --- Common definitons for Kubed -*- lexical-binding: t; -*- + +;; Copyright (C) 2024-2026 Free Software Foundation, Inc. + +;; Author: Eshel Yaron +;; Keywords: tools + +;;; Commentary: + +;; This library provides definitions that both `kubed' and `kubed-tramp' +;; require. + +;;; Code: + +(defvar kubed-tramp-method "kubedv2" ;Versioned, for compatibility. + ;; (find-file "/kubedv2:CONTEXT%NAMESPACE%POD%CONTAINER:/some/file") + "Name of the Kubed Tramp method.") + +(defcustom kubed-kubectl-program "kubectl" + "Name of `kubectl' executable to use for interacting with Kubernetes." + :type 'string + :group 'kubed) + +(provide 'kubed-common) +;;; kubed-tramp.el ends here diff --git a/elpa/kubed-0.6.1/kubed-pkg.el b/elpa/kubed-0.6.1/kubed-pkg.el new file mode 100644 index 00000000..2a2f2d47 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from kubed.el -*- mode: lisp-data; no-byte-compile: t; lexical-binding:t -*- +(define-package "kubed" "0.6.1" "Kubernetes, Emacs, done!" '((emacs "29.1")) :commit "2f231466790c5db18a6e1479e3c67945d43cbf94" :authors '(("Eshel Yaron" . "me@eshelyaron.com")) :maintainer '("Eshel Yaron" . "~eshel/kubed-devel@lists.sr.ht") :keywords '("tools" "kubernetes" "containers") :url "https://eshelyaron.com/kubed.html") diff --git a/elpa/kubed-0.6.1/kubed-tramp.el b/elpa/kubed-0.6.1/kubed-tramp.el new file mode 100644 index 00000000..12d0f83d --- /dev/null +++ b/elpa/kubed-0.6.1/kubed-tramp.el @@ -0,0 +1,222 @@ +;;; kubed-tramp.el --- Kubed Tramp integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2024-2026 Free Software Foundation, Inc. + +;; Author: Eshel Yaron +;; Keywords: tools + +;;; Commentary: + +;; This library provides Tramp integration for Kubed. This is similar +;; to the built-in "kubernetes" Tramp method from tramp-container.el, +;; except that the Kubed method always requires the container name and +;; Kubernetes namespace to be specified, as well a `kubectl' context. +;; In other words, the filename syntax of this method is fully explicit. +;; An explicit syntax is useful when juggling between different contexts +;; and namespaces with Kubed; on the other hand, for finding a remote +;; file with C-x C-f, the concise syntax of the built-in "kubernetes" +;; method is probably more convenient. + +;;; Code: + +(require 'kubed-common) +(require 'tramp) + +(defun kubed-tramp--unhex (x) + ;; Simplified version of `url-unhex'. + (if (> x ?9) (+ 10 (- x ?A)) (- x ?0))) + +(defun kubed-tramp--decode-context-name (str) + ;; Adopted from `url-unhex-string'. + (let ((tmp "") (case-fold-search nil)) + (while (string-match "[.][0-9A-F][0-9A-F]" str) + (let* ((start (match-beginning 0)) + (ch1 (kubed-tramp--unhex (elt str (+ start 1)))) + (code (+ (* 16 ch1) + (kubed-tramp--unhex (elt str (+ start 2)))))) + (setq tmp (concat tmp (substring str 0 start) (byte-to-string code)) + str (substring str (match-end 0))))) + (concat tmp str))) + +(defun kubed-tramp--v2-context (vec) + "Extract the context name from a kubernetes host name in VEC." + (or (when-let ((host (and vec (tramp-file-name-host vec)))) + (shell-quote-argument + (decode-coding-string + (kubed-tramp--decode-context-name (nth 0 (split-string host "%"))) + 'utf-8))) + "")) + +(defun kubed-tramp--context (vec) + "Extract the context name from a kubernetes host name in VEC." + (or (when-let ((host (and vec (tramp-file-name-host vec)))) + (nth 0 (split-string host "%"))) + "")) + +(defun kubed-tramp--namespace (vec) + "Extract the namespace from a kubernetes host name in VEC." + (or (when-let ((host (and vec (tramp-file-name-host vec)))) + (nth 1 (split-string host "%"))) + "")) + +(defun kubed-tramp--pod (vec) + "Extract the pod name from a kubernetes host name in VEC." + (or (when-let ((host (and vec (tramp-file-name-host vec)))) + (nth 2 (split-string host "%"))) + "")) + +(defun kubed-tramp--container (vec) + "Extract the container name from a kubernetes host name in VEC." + (or (when-let ((host (and vec (tramp-file-name-host vec)))) + (nth 3 (split-string host "%"))) + "")) + +;;;###autoload +(defun kubed-tramp-context (file-name) + "Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME." + ;; TODO: Dispatch based on method version. The following is intended + ;; for v2, although it also works for v1 in most cases. + (decode-coding-string + (kubed-tramp--decode-context-name + (nth 0 (split-string + (tramp-file-name-host (tramp-dissect-file-name file-name)) + "%"))) + 'utf-8)) + +;;;###autoload +(defun kubed-tramp-namespace (file-name) + "Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME." + (nth 1 (split-string + (tramp-file-name-host (tramp-dissect-file-name file-name)) "%"))) + +;;;###autoload +(defun kubed-tramp-assert-support () + "Check if Kubed Tramp support is available, throw `user-error' if not." + (unless (assoc kubed-tramp-method tramp-methods) + (user-error "Kubed Tramp support requires Tramp version 2.7 or later"))) + +(defun kubed-tramp--previous-hop (vec) + (or + ;; Previous hop explicit in VEC. + (when-let ((hop (tramp-file-name-hop vec))) + (tramp-make-tramp-file-name + (tramp-dissect-hop-name (tramp-file-name-hop vec)))) + ;; Implicit previous hop registered in `tramp-default-proxies-alist'. + (seq-some + (lambda (item) + ;; Here we replicate what `tramp-compute-multi-hops' does... + (when (and + ;; Host. + (string-match-p + (or (eval (nth 0 item) t) "") + (or (tramp-file-name-host-port vec) "")) + ;; User. + (string-match-p + (or (eval (nth 1 item) t) "") + (or (tramp-file-name-user-domain vec) ""))) + (tramp-format-spec + (eval (nth 2 item) t) + (format-spec-make + ?u (or (tramp-file-name-user vec) "") + ?h (or (tramp-file-name-host vec) ""))))) + tramp-default-proxies-alist))) + +(defun kubed-tramp--login-program (vec) + "Return `kubectl' program to use for connection VEC. + +Respect the connection-local value of user option `kubed-kubectl-program'." + (if-let ((hop-dir (kubed-tramp--previous-hop vec))) + (let ((default-directory hop-dir)) + (connection-local-value kubed-kubectl-program 'kubed)) + kubed-kubectl-program)) + +(defun kubed-tramp-get-method-parameter-advice (of vec param &rest rest) + (if (and (eq param 'tramp-login-program) + (member (tramp-file-name-method vec) + `(,kubed-tramp-method + ;; Old versions: + "kubedv1"))) + ;; When Tramp asks how to invoke kubectl on our behalf, + ;; point it to the up-to-date (and possibly connection-local) + ;; value of `kubed-kubectl-program'. + (kubed-tramp--login-program vec) + (apply of vec param rest))) + +;;;###autoload +(defun kubed-tramp-enable () + "Enable Kubed integration with Tramp." + (when (boundp 'tramp-extra-expand-args) ; Tramp 2.7+ + + (let ((params `(;; Note that this "hardcodes" the current value of + ;; `kubed-kubectl-program', which is the common + ;; practice with Tramp methods, but it is not what + ;; we want. But that's ok: the value we put here is + ;; not actually used, because we install an advice + ;; that gives the up-to-date (and possibly + ;; connection-local, for remote hosts) value of + ;; `kubed-kubectl-program' when Tramp asks. + (tramp-login-program "%b") + (tramp-login-args (("exec") + ("--context" "%x") + ("--namespace" "%y") + ("-c" "%a") + ("%h") + ("-it") + ("--") + ("%l"))) + (tramp-direct-async (,tramp-default-remote-shell "-c")) + (tramp-remote-shell ,tramp-default-remote-shell) + (tramp-remote-shell-login ("-l")) + (tramp-remote-shell-args ("-i" "-c"))))) + + ;; Old version. + (setf (alist-get "kubedv1" tramp-methods nil nil #'string=) params) + + (connection-local-set-profile-variables + 'kubed-tramp-connection-local-default-profile + '((tramp-extra-expand-args + ?b (kubed-tramp--login-program (car tramp-current-connection)) + ?a (kubed-tramp--container (car tramp-current-connection)) + ?h (kubed-tramp--pod (car tramp-current-connection)) + ?x (kubed-tramp--context (car tramp-current-connection)) + ?y (kubed-tramp--namespace (car tramp-current-connection))))) + + (connection-local-set-profiles + '(:application tramp :protocol "kubedv1") + 'kubed-tramp-connection-local-default-profile) + + ;; New version. + (setf (alist-get kubed-tramp-method tramp-methods nil nil #'string=) params) + + (connection-local-set-profile-variables + 'kubed-tramp-v2-connection-local-default-profile + '((tramp-extra-expand-args + ?b (kubed-tramp--login-program (car tramp-current-connection)) + ?a (kubed-tramp--container (car tramp-current-connection)) + ?h (kubed-tramp--pod (car tramp-current-connection)) + ?x (kubed-tramp--v2-context (car tramp-current-connection)) + ?y (kubed-tramp--namespace (car tramp-current-connection))))) + + (connection-local-set-profiles + `(:application tramp :protocol ,kubed-tramp-method) + 'kubed-tramp-v2-connection-local-default-profile)) + + (when (or (version< tramp-version "2.8.1.4") + (not (fboundp 'tramp-suppress-remote-file-name-inhibit-cache))) + ;; Arg expansion for `tramp-login-program' was added in 2.8.1.4; + ;; for earlier versions we advise `tramp-get-method-parameter' to + ;; get the right value. + ;; (See https://lists.gnu.org/r/tramp-devel/2026-03/msg00000.html) + ;; The check for `tramp-suppress-remote-file-name-inhibit-cache' + ;; is for the benefit of users of the development version of Emacs + ;; (31.0.50, which has `tramp-version' 2.8.2-pre) prior to the + ;; addition of the new arg expansion, since this function happened + ;; to be added shortly after. + (advice-add 'tramp-get-method-parameter :around + #'kubed-tramp-get-method-parameter-advice + '((name . kubed)))))) + +;;;###autoload (with-eval-after-load 'tramp (kubed-tramp-enable)) + +(provide 'kubed-tramp) +;;; kubed-tramp.el ends here diff --git a/elpa/kubed-0.6.1/kubed-transient.el b/elpa/kubed-0.6.1/kubed-transient.el new file mode 100644 index 00000000..d03a2b93 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed-transient.el @@ -0,0 +1,622 @@ +;;; kubed-transient.el --- Kubernetes transient menus -*- lexical-binding: t; -*- + +;; Copyright (C) 2024-2026 Free Software Foundation, Inc. + +;; Author: Eshel Yaron +;; Keywords: tools + +;;; Commentary: + +;; This library extends Kubed with transient menus for various +;; Kubernetes operations. + +;;; Code: + +(require 'kubed) +(require 'transient) + +(defun kubed-transient-read-date (prompt default _history) + "Prompt with PROMPT for a date, defaulting to DEFAULT. + +Return an RFC3339 string representation of the selected date." + (require 'org) + (when (fboundp 'org-read-date) + (format-time-string "%Y-%m-%dT%H:%M:%S%:z" + (org-read-date 'with-time t nil prompt default)))) + +(defun kubed-transient-read-context (prompt _initial-input _history) + "Prompt with PROMPT for Kubernetes context." + (kubed-read-context prompt (kubed-local-context))) + +(defun kubed-transient-read-namespace (prompt _initial-input _history) + "Prompt with PROMPT for Kubernetes namespace." + (let ((context (or (seq-some (lambda (s) + (and (cl-typep s 'transient-infix) + (equal (oref s argument) "--context=") + (oref s value))) + transient--suffixes) + (kubed-local-context)))) + (kubed-read-namespace prompt (kubed--namespace context) nil context))) + +(defun kubed-transient-read-ingressclass (prompt _initial-input _history) + "Prompt with PROMPT for Kubernetes ingress class." + (kubed-read-ingressclass prompt)) + +(defun kubed-transient-read-service-and-port (prompt _initial-input _history) + "Prompt with PROMPT for Kubernetes service and port number." + (let ((service (kubed-read-service prompt))) + (concat service ":" (number-to-string (read-number "Port number: "))))) + +(defun kubed-transient-read-resource-definition-file-name + (_prompt _initial-input _history) + "Read and return Kubernetes resource definition file name." + (kubed-read-resource-definition-file-name)) + +;;;###autoload (autoload 'kubed-transient "kubed-transient" nil t) +(transient-define-prefix kubed-transient () + "Perform Kubernetes operation." + ["Kubernetes" + [ :pad-keys t + ("RET" "Display" kubed-transient-display) + ("+" "Create" kubed-transient-create) + ("*" "Apply" kubed-transient-apply) + ("D" "Delete" kubed-transient-delete)] + [("e" "Edit" kubed-transient-edit) + ("r" "Run" kubed-transient-run) + ("a" "Attach" kubed-transient-attach) + ("X" "Exec" kubed-transient-exec)] + [("l" "Logs" kubed-transient-logs) + ("d" "Diff" kubed-transient-diff) + ("P" "Patch" kubed-transient-patch) + ("R" "Rollout" kubed-transient-rollout)] + [("$" "Scale" kubed-transient-scale-deployment) + (":" "Proxy" kubed-transient-proxy) + ("E" "Explain" kubed-explain) + ("!" "Command line" kubed-kubectl-command)]]) + +(defmacro kubed-transient-logs-for-resource (resource &optional plural) + "Define transient menu for showing logs for Kubernetes RESOURCE. + +Optional argument PLURAL is the plural form of RESOURCE. If nil, it +defaults to \"RESOURCEs\"." + (setq plural (or plural (concat resource "s"))) + (let ((name (intern (concat "kubed-transient-logs-for-" resource)))) + `(transient-define-prefix ,name (&optional value) + ,(format "Show logs for a Kubernetes %s." resource) + [,(format "Kubernetes Logs for %s\n" (capitalize resource)) + ["Actions" + ("l" "Show Logs" ,(intern (concat "kubed-logs-for-" resource))) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + :pad-keys t + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-b" "Limit bytes" "--limit-bytes=" + :prompt "Bytes limit: " :reader transient-read-number-N+) + ("-t" "Limit lines" "--tail=" + :prompt "Lines limit: " :reader transient-read-number-N+) + ("-S" "Since time" "--since-time=" + :prompt "Since time: " :reader kubed-transient-read-date) + ("/" ,(format "%s" (capitalize resource)) ,(concat plural "/") + :class transient-option + :always-read t + :prompt "Show logs for" + :reader (lambda (prompt _initial-input _history) + (let* ((context (seq-some (lambda (s) + (and (cl-typep s 'transient-infix) + (equal (oref s argument) "--context=") + (oref s value))) + transient--suffixes)) + (namespace (seq-some (lambda (s) + (and (cl-typep s 'transient-infix) + (equal (oref s argument) "--namespace=") + (oref s value))) + transient--suffixes)) + (default (seq-some (lambda (s) + (and (cl-typep s 'transient-infix) + (equal (oref s argument) ,(concat plural "/")) + (oref s value))) + transient--suffixes))) + (,(intern (format "kubed-read-%s" resource)) + prompt default nil context namespace))))] + ["Switches" + ("-A" "All containers" "--all-containers") + ("-f" "Stream logs" "--follow") + ("-P" "Add pod and container" "--prefix") + ("-T" "Add timestamps" "--timestamps")]] + (interactive + (list (append + (kubed-transient-args) + (when-let ((res (tabulated-list-get-id))) + (list (concat ,(concat plural "/") res))) + (unless (zerop kubed-logs-tail-lines) + (list (format "--tail=%d" kubed-logs-tail-lines))) + (when kubed-logs-follow (list "--follow"))))) + (transient-setup ',name nil nil + :value value + :scope '("logs"))))) + +;;;###autoload (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t) +(kubed-transient-logs-for-resource "pod") + +;;;###autoload (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t) +(kubed-transient-logs-for-resource "deployment") + +;;;###autoload (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t) +(kubed-transient-logs-for-resource "service") + +;;;###autoload (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t) +(kubed-transient-logs-for-resource "job") + +;;;###autoload (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t) +(kubed-transient-logs-for-resource "replicaset") + +;;;###autoload (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t) +(kubed-transient-logs-for-resource "daemonset") + +;;;###autoload (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t) +(kubed-transient-logs-for-resource "statefulset") + +;;;###autoload (autoload 'kubed-transient-logs "kubed-transient" nil t) +(transient-define-prefix kubed-transient-logs (&optional value) + "Show logs for containers running in Kubernetes." + ["Kubernetes Logs\n" + ["Kinds" + ("p" "Pod" kubed-transient-logs-for-pod) + ("d" "Deployment" kubed-transient-logs-for-deployment) + ("j" "Job" kubed-transient-logs-for-job) + ("s" "Service" kubed-transient-logs-for-service) + ("l" "Any type" kubed-logs) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-b" "Limit bytes" "--limit-bytes=" + :prompt "Bytes limit: " :reader transient-read-number-N+) + ("-t" "Limit lines" "--tail=" + :prompt "Lines limit: " :reader transient-read-number-N+) + ("-S" "Since time" "--since-time=" + :prompt "Since time: " :reader kubed-transient-read-date)] + ["Switches" + ("-A" "All containers" "--all-containers") + ("-f" "Stream logs" "--follow") + ("-P" "Add pod and container" "--prefix") + ("-T" "Add timestamps" "--timestamps")]] + (interactive + (list (append + (kubed-transient-args) + (unless (zerop kubed-logs-tail-lines) + (list (format "--tail=%d" kubed-logs-tail-lines))) + (when kubed-logs-follow (list "--follow"))))) + (transient-setup 'kubed-transient-logs nil nil + :value value + :scope '("logs"))) + +;;;###autoload (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t) +(transient-define-prefix kubed-transient-scale-deployment () + "Scale Kubernetes deployments." + ["Kubernetes Scale Deployment\n" + ["Action" + ("$" "Scale" kubed-scale-deployment) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-r" "Replicas" "--replicas=" + :prompt "Number of replicas: " :reader transient-read-number-N+)]] + (interactive) + (transient-setup 'kubed-transient-scale-deployment nil nil + :scope '("scale" "deployment"))) + +;;;###autoload (autoload 'kubed-transient-proxy "kubed-transient" nil t) +(transient-define-prefix kubed-transient-proxy () + "Create a proxy between localhost and the Kubernetes API server." + ["Kubernetes Proxy\n" + ["Action" + (":" "Start proxy" kubed-proxy) + ("|" "Stop proxy" kubed-stop-proxy) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-a" "Address" "--address=" + :prompt "Local proxy address: ") + ("-p" "Port" "--port=" + :prompt "Local proxy port: " :reader transient-read-number-N0) + ("-w" "WWW directory" "--www=" + :prompt "Local WWW directory: " :reader transient-read-existing-directory) + ("-P" "WWW prefix" "--www-prefix=" + :prompt "WWW prefix: ") + ("-A" "API prefix" "--api-prefix=" + :prompt "API prefix: ")]] + (interactive) + (transient-setup 'kubed-transient-proxy nil nil + :scope '("proxy"))) + +;;;###autoload (autoload 'kubed-transient-rollout "kubed-transient" nil t) +(transient-define-prefix kubed-transient-rollout () + "Manage Kubernetes deployments." + ["Kubernetes Rollout\n" + ["Actions" + ("W" "Watch" kubed-watch-deployment-status) + ("R" "Restart" kubed-restart-deployment) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-rollout nil nil + :scope '("rollout"))) + +;;;###autoload (autoload 'kubed-transient-attach "kubed-transient" nil t) +(transient-define-prefix kubed-transient-attach () + "Attach to running process in container in Kubernetes pod." + ["Kubernetes Attach\n" + ["Actions" + ("a" "Attach" kubed-attach) + ("!" "Command line" kubed-kubectl-command)] + ["Switches" + ("-i" "Open stdin" "--stdin") + ("-t" "Allocate TTY" "--tty")] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-attach nil nil + :value '("--stdin" "--tty") + :scope '("attach"))) + +;;;###autoload (autoload 'kubed-transient-diff "kubed-transient" nil t) +(transient-define-prefix kubed-transient-diff () + "Display difference between Kubernetes resource definition and current state." + ["Kubernetes Diff\n" + ["Actions" + ("d" "Diff" kubed-diff) + ("!" "Command line" kubed-kubectl-command)] + ["Switches" + ("-M" "Include managed fields" "--show-managed-fields")] + ["Options" + ("-f" "Definition file" "--filename=" + :reader kubed-transient-read-resource-definition-file-name) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-diff nil nil + :scope '("diff"))) + +;;;###autoload (autoload 'kubed-transient-exec "kubed-transient" nil t) +(transient-define-prefix kubed-transient-exec () + "Execute command in Kubernetes pod." + ["Kubernetes Exec\n" + ["Actions" + ("X" "Execute" kubed-exec) + ("!" "Command line" kubed-kubectl-command)] + ["Switches" + ("-i" "Open stdin" "--stdin") + ("-t" "Allocate TTY" "--tty")] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("--" "Command" "-- =" + :prompt "Command: ")]] + (interactive) + (transient-setup 'kubed-transient-exec nil nil + :value '("--stdin" "--tty") + :scope '("exec"))) + +;;;###autoload (autoload 'kubed-transient-run "kubed-transient" nil t) +(transient-define-prefix kubed-transient-run () + "Run container image in a Kubernetes pod." + ["Kubernetes Run\n" + ["Actions" + ("r" "Run" kubed-run) + ("!" "Command line" kubed-kubectl-command)] + ["Switches" + ("-A" "Attach" "--attach") + ("-i" "Open stdin" "--stdin") + ("-t" "Allocate TTY" "--tty") + ("-R" "Remove after exit" "--rm") + ("-c" "Override container command" "--command")] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-I" "Image" "--image=" + :prompt "Image to deploy: ") + ("-p" "Port" "--port=" + :prompt "Port to expose: " :reader transient-read-number-N+) + ("-E" "Env vars" "--env=" + :prompt "Set environment VAR=VAL: " + :multi-value repeat) + ("--" "Arguments" "-- =" + :prompt "Arguments for container command: ")]] + (interactive) + (transient-setup 'kubed-transient-run nil nil + :scope '("run"))) + +;;;###autoload (autoload 'kubed-transient-apply "kubed-transient" nil t) +(transient-define-prefix kubed-transient-apply () + "Apply configuration to Kubernetes resource." + ["Kubernetes Apply\n" + ["Actions" + ("*" "Apply" kubed-apply) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-f" "Definition file" "--filename=" + :reader kubed-transient-read-resource-definition-file-name) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-apply nil nil + :scope '("apply"))) + +;;;###autoload (autoload 'kubed-transient-patch "kubed-transient" nil t) +(transient-define-prefix kubed-transient-patch () + "Apply patch to Kubernetes resource." + ["Kubernetes Patch\n" + ["Actions" + ("P" "Patch" kubed-patch) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-t" "Patch type" "--type=" + :prompt "Patch type: " + :choices ("strategic" "merge" "json"))]] + (interactive) + (transient-setup 'kubed-transient-patch nil nil + :scope '("patch"))) + +;;;###autoload (autoload 'kubed-transient-create "kubed-transient" nil t) +(transient-define-prefix kubed-transient-create () + "Create Kubernetes resource." + ["Kubernetes Create\n" + ["Kinds" + ("p" "Pod" kubed-create-pod) + ("d" "Deployment" kubed-transient-create-deployment) + ("j" "Job" kubed-transient-create-job) + ("c" "CronJob" kubed-transient-create-cronjob) + ("s" "Service" kubed-create-service)] + ["More" + :pad-keys t + ("S" "Secret" kubed-create-secret) + ("N" "Namespace" kubed-create-namespace) + ("i" "Ingress" kubed-transient-create-ingress) + ("+" "Any type" kubed-create) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-f" "Definition file" "--filename=" + :reader kubed-transient-read-resource-definition-file-name) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-create nil nil + :scope '("create"))) + +;;;###autoload (autoload 'kubed-transient-display "kubed-transient" nil t) +(transient-define-prefix kubed-transient-display () + "Display Kubernetes resource." + ["Kubernetes Display\n" + ["Kinds" + ("p" "Pod" kubed-display-pod) + ("d" "Deployment" kubed-display-deployment) + ("j" "Job" kubed-display-job) + ("c" "CronJob" kubed-display-cronjob) + ("s" "Service" kubed-display-service)] + ["More" + :pad-keys t + ("S" "Secret" kubed-display-secret) + ("N" "Namespace" kubed-display-namespace) + ("i" "Ingress" kubed-display-ingress) + ("RET" "Any type" kubed-display-resource) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-display nil nil + :scope '("get"))) + +;;;###autoload (autoload 'kubed-transient-edit "kubed-transient" nil t) +(transient-define-prefix kubed-transient-edit () + "Edit Kubernetes resource." + ["Kubernetes Edit\n" + ["Kinds" + ("p" "Pod" kubed-edit-pod) + ("d" "Deployment" kubed-edit-deployment) + ("j" "Job" kubed-edit-job) + ("c" "CronJob" kubed-edit-cronjob) + ("s" "Service" kubed-edit-service)] + ["More" + :pad-keys t + ("S" "Secret" kubed-edit-secret) + ("N" "Namespace" kubed-edit-namespace) + ("i" "Ingress" kubed-edit-ingress) + ("RET" "Any type" kubed-edit-resource) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-edit nil nil + :scope '("edit"))) + +;;;###autoload (autoload 'kubed-transient-delete "kubed-transient" nil t) +(transient-define-prefix kubed-transient-delete () + "Delete Kubernetes resource." + ["Kubernetes Delete\n" + ["Kinds" + ("p" "Pod" kubed-delete-pods) + ("d" "Deployment" kubed-delete-deployments) + ("j" "Job" kubed-delete-jobs) + ("c" "CronJob" kubed-delete-cronjobs) + ("s" "Service" kubed-delete-services)] + ["More" + :pad-keys t + ("S" "Secret" kubed-delete-secrets) + ("N" "Namespace" kubed-delete-namespaces) + ("i" "Ingress" kubed-delete-ingresses) + ("D" "Any type" kubed-delete-resources) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context)]] + (interactive) + (transient-setup 'kubed-transient-delete nil nil + :scope '("delete"))) + +;;;###autoload (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t) +(transient-define-prefix kubed-transient-create-cronjob () + "Create Kubernetes cronjob." + ["Kubernetes Create CronJob\n" + ["Actions" + ("+" "Create" kubed-create-cronjob) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-I" "Image" "--image=" + :prompt "Image to run: ") + ("-S" "Schedule" "--schedule=" + :prompt "Cron schedule: ") + ("--" "Command" "-- =" + :prompt "Command: ")]] + (interactive) + (transient-setup 'kubed-transient-create-cronjob nil nil + :scope '("create" "cronjob"))) + +;;;###autoload (autoload 'kubed-transient-create-ingress "kubed-transient" nil t) +(transient-define-prefix kubed-transient-create-ingress () + "Create Kubernetes ingress." + ["Kubernetes Create Ingress\n" + ["Actions" + ("+" "Create" kubed-create-ingress) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-c" "Class" "--class=" + :prompt "Class" :reader kubed-transient-read-ingressclass) + ("-d" "Default backend service" "--default-backend=" + :prompt "Default backend service" + :reader kubed-transient-read-service-and-port) + ("-a" "Annotation" "--annotation=" + :prompt "Ingress annotations: " + :multi-value repeat) + ("-r" "Rule" "--rule=" + :prompt "Ingress rule: ")]] + (interactive) + (transient-setup 'kubed-transient-create-ingress nil nil + :scope '("create" "ingress"))) + +;;;###autoload (autoload 'kubed-transient-create-deployment "kubed-transient" nil t) +(transient-define-prefix kubed-transient-create-deployment () + "Create Kubernetes deployment." + ["Kubernetes Create Deployment\n" + ["Actions" + ("+" "Create" kubed-create-deployment) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-r" "Replicas" "--replicas=" + :prompt "Number of replicas: " :reader transient-read-number-N+) + ("-I" "Image" "--image=" + :prompt "Images to deploy: " + :multi-value repeat) + ("-p" "Port" "--port=" + :prompt "Port to expose: " :reader transient-read-number-N+) + ("--" "Command" "-- =" + :prompt "Command: ")]] + (interactive) + (transient-setup 'kubed-transient-create-deployment nil nil + :scope '("create" "deployment"))) + +;;;###autoload (autoload 'kubed-transient-create-job "kubed-transient" nil t) +(transient-define-prefix kubed-transient-create-job () + "Create Kubernetes job." + ["Kubernetes Create Job\n" + ["Actions" + ("+" "Create" kubed-create-job) + ("c" "Create from cronjob" kubed-create-job-from-cronjob) + ("!" "Command line" kubed-kubectl-command)] + ["Options" + ("-n" "Namespace" "--namespace=" + :prompt "Namespace" :reader kubed-transient-read-namespace) + ("-C" "Context" "--context=" + :prompt "Context" :reader kubed-transient-read-context) + ("-I" "Image" "--image=" + :prompt "Image to run: ") + ("--" "Command" "-- =" + :prompt "Command: ")]] + (interactive) + (transient-setup 'kubed-transient-create-job nil nil + :scope '("create" "job"))) + +;;;###autoload (autoload 'kubed-list-transient "kubed-transient" nil t) +(transient-define-prefix kubed-list-transient () + "Help for Kubernetes resource list buffers." + ;; TODO: Add a type-specific group with `:setup-children'. + ["Kubernetes Resources:" + ["Select" + :pad-keys t + ("RET" "Select" kubed-list-select-resource) + ("C-o" "Display" kubed-list-display-resource :transient t) + ("e" "Edit" kubed-list-edit :transient t) + ("w" "Copy name" kubed-list-copy-as-kill :transient t) + ("!" "Command line" kubed-list-kubectl-command :transient t)] + ["Delete" + ("D" "Delete" kubed-list-delete :transient t) + ("d" "Mark" kubed-list-mark-for-deletion :transient t) + ("u" "Unmark" kubed-list-unmark :transient t) + ("x" "Delete marked" kubed-list-delete-marked :transient t) + ("+" "Create" kubed-list-create :transient t)] + ["Table" + ("|" "Fit column" kubed-list-fit-column-width-to-content :transient t) + ("}" "Widen column" tabulated-list-widen-current-column :transient t) + ("{" "Narrow column" tabulated-list-narrow-current-column :transient t) + ("S" "Sort" tabulated-list-sort :transient t) + ("/" "Filter" kubed-list-set-filter :transient t)] + ["Movement" + :pad-keys t + ("n" "Next line" next-line :transient t) + ("p" "Previous line" previous-line :transient t) + ("TAB" "Next column" kubed-list-next-column :transient t) + ("S-TAB" "Previous column" kubed-list-previous-column :transient t) + ("g" "Update" kubed-list-update :transient t)]] + ["Type Specific" + :class transient-columns + :setup-children + (lambda (_) + (transient-parse-suffixes 'kubed-list-transient + kubed-list-transient-extra-suffixes))]) + +(provide 'kubed-transient) +;;; kubed-transient.el ends here diff --git a/elpa/kubed-0.6.1/kubed.el b/elpa/kubed-0.6.1/kubed.el new file mode 100644 index 00000000..4c276fd0 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed.el @@ -0,0 +1,3718 @@ +;;; kubed.el --- Kubernetes, Emacs, done! -*- lexical-binding: t; -*- + +;; Copyright (C) 2024-2026 Free Software Foundation, Inc. + +;; Author: Eshel Yaron +;; Maintainer: Eshel Yaron <~eshel/kubed-devel@lists.sr.ht> +;; Keywords: tools kubernetes containers +;; URL: https://eshelyaron.com/kubed.html +;; Package-Version: 0.6.1 +;; Package-Requires: ((emacs "29.1")) + +;;; Commentary: + +;; This library defines commands for interacting with Kubernetes +;; resources, such as Kubernetes pods, services, deployments, and more. +;; +;; Use `kubed-display-pod' to display a Kubernetes pod, +;; `kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and +;; `kubed-list-pods' to see a menu of all pods. You can create new pods +;; from YAML or JSON files with `kubed-create-pod'. +;; +;; Similar commands are defined for other types of resources as well. +;; +;; This library interacts with Kubernetes via `kubectl', and uses the +;; current `kubectl' context and namespace by default. To change your +;; current context or namespace, use commands `kubed-use-context' and +;; `kubed-set-namespace' respectively; you can also interact with +;; resources in other namespaces without changing your default +;; namespace, for example you can call `kubed-list-pods' with a prefix +;; argument to choose another namespace for listing pods. The prefix +;; keymap `kubed-prefix-map' gives you quick access to these and other +;; useful commands, you may want to bind it globally to a convenient key +;; with `keymap-global-set': +;; +;; (keymap-global-set "C-c k" 'kubed-prefix-map) +;; +;; In addition, the command `kubed-transient' lets you explore various +;; Kubernetes operations with a transient menu interface. You may also +;; want to enable `kubed-menu-bar-mode', which add a "Kubernetes" menu +;; to your menu-bar with many useful entries. +;; +;; If you want to work with more or different types of Kubernetes +;; resources, use the macro `kubed-define-resource'. This macro defines +;; some common functions and commands that'll get you started with ease. +;; +;; For more information, see the Kubed manual at (info "(kubed)Top"), or +;; online at https://eshelyaron.com/kubed.html + +;;; Code: + +(require 'kubed-common) + +(defgroup kubed nil + "Kubernetes interface." + :group 'tools) + +(defvar kubed-default-context-and-namespace nil) +(make-obsolete-variable + 'kubed-default-context-and-namespace + 'kubed-default-context-and-namespace-alist + "Kubed 0.6.0") + +(defcustom kubed-default-context-and-namespace-alist + `((nil . ,kubed-default-context-and-namespace)) + "Alist mapping hosts to their default `kubectl' context and Kubernetes namespace. + +Each alist entry is (HOST . CONTEXT-AND-NAMESPACE), where HOST is either +a remote host identifier (as returned by `file-remote-p') or nil which +represents the local host, and CONTEXT-AND-NAMESPACE is either a cons +cell (CONTEXT . NAMESPACE), or nil. If it is nil, Kubed initializes +CONTEXT-AND-NAMESPACE to a non-nil value next time Kubed consults it." + :type '(alist + :key-type + (choice (const :tag "Local host" nil) + (string :tag "Remote host")) + :value-type + (choice (const :tag "Initialize from `kubectl' on first use" nil) + (cons :tag "Context and namespace" + (string :tag "Context") + (string :tag "Namespace"))))) + +(defcustom kubed-yaml-setup-hook '(yaml-ts-mode view-mode) + "List of functions to call in Kubernetes resource description YAML buffers. + +The first function in the list should normally be the major mode to use, +by default it is `yaml-ts-mode'." + :type 'hook) + +(defcustom kubed-logs-setup-hook '(view-mode) + "List of functions to call when setting up Kubernetes pod logs buffers." + :type 'hook) + +(defcustom kubed-logs-tail-lines 128 + "Number of most recent log lines to fetch and show in Kubernetes logs buffers. + +The value 0 says to fetch and show all available log lines without limit." + :type '(natnum :tag "Number of lines (0 for all)")) + +(defcustom kubed-logs-follow t + "Whether to \"follow\" new logs in Kubernetes logs buffers." + :type 'boolean) + +(defcustom kubed-name-column '("Name" 48 t) + "Specification of resource name column in Kubernetes resource list buffers." + :type '(list string natnum boolean)) + +(defsubst kubed-kubectl-program () + "Return the connection-local value of variable `kubed-kubectl-program'." + (connection-local-value kubed-kubectl-program 'kubed)) + +(defvar kubed--data nil) + +(defun kubed--alist (host type context namespace) + "Return information about resources of type TYPE for HOST, CONTEXT and NAMESPACE." + (alist-get namespace + (alist-get type + (alist-get context + (alist-get host kubed--data nil nil #'equal) + nil nil #'string=) + nil nil #'string=) + nil nil #'equal)) + +(gv-define-setter kubed--alist (value host type context namespace) + `(setf (alist-get ,namespace + (alist-get ,type + (alist-get ,context + (alist-get ,host kubed--data nil nil #'equal) + nil nil #'string=) + nil nil #'string=) + nil nil #'equal) + ,value)) + +(defvar kubed--columns nil) + +(defun kubed-update (type context &optional namespace host) + "Update list of resources of type TYPE in CONTEXT and NAMESPACE." + (unless host (setq host (file-remote-p default-directory))) + (when (process-live-p (alist-get 'process (kubed--alist host type context namespace))) + (user-error "Update in progress")) + (let* ((out (get-buffer-create (format " *kubed-get-%s*" type))) + (err (get-buffer-create (format " *kubed-get-%s-stderr*" type))) + (columns (alist-get type kubed--columns '(("NAME:.metadata.name")) nil #'string=))) + (with-current-buffer out (erase-buffer)) + (setf (alist-get 'process (kubed--alist host type context namespace)) + (make-process + :name (format "*kubed-get-%s*" type) + :buffer out + :stderr err + :file-handler t + :command (append + (list (kubed-kubectl-program) "get" type + "--context" context + (format "--output=custom-columns=%s" + (mapconcat #'car columns ","))) + (when namespace (list "--namespace" namespace))) + :sentinel + (lambda (_proc status) + (cond + ((string= status "finished\n") + (let (new offsets eol) + (with-current-buffer out + (goto-char (point-min)) + (setq eol (pos-eol)) + (while (re-search-forward "[^ ]+" eol t) + (push (1- (match-beginning 0)) offsets)) + (setq offsets (nreverse offsets)) + (forward-char 1) + (while (not (eobp)) + (let ((cols nil) + (beg (car offsets)) + (ends (append (cdr offsets) + (list (- (pos-eol) (point)))))) + (dolist (column columns) + (let ((str (string-trim (buffer-substring + (+ (point) beg) + (+ (point) (car ends)))))) + (push (if-let ((f (cdr column))) (funcall f str) str) + cols) + (setq beg (pop ends)))) + (push (nreverse cols) new)) + (forward-line 1))) + (setf (kubed--alist host type context namespace) + (list (cons 'resources + (mapcar (lambda (c) (list (car c) (apply #'vector c))) + new)))) + (let ((bufs nil)) + (dolist (buf (buffer-list)) + (and (equal (buffer-local-value 'kubed-list-type buf) type) + (equal (buffer-local-value 'kubed-list-context buf) context) + (equal (buffer-local-value 'kubed-list-namespace buf) namespace) + (equal (file-remote-p + (buffer-local-value 'default-directory buf)) + host) + (with-current-buffer buf + (when (derived-mode-p 'kubed-list-mode) + (revert-buffer) + (when-let ((win (get-buffer-window))) + (set-window-point win (point)) + (push buf bufs)))))) + (walk-windows + (lambda (win) + (let ((buf (window-buffer win))) + (when (memq buf bufs) + (set-window-point + win (with-current-buffer buf (point)))))))) + (message (format "Updated Kubernetes %S." type)))) + ((string= status "exited abnormally with code 1\n") + (with-current-buffer err + (goto-char (point-max)) + (insert "\n" status)) + (display-buffer err)))))))) + +(defvar-local kubed-display-resource-info nil + "Information about Kubernetes resource that current buffer displays. + +The value is a list (TYPE NAME CONTEXT NAMESPACE), where TYPE is the +type of the resource, NAME is the name of the resource, CONTEXT is the +`kubectl' context to use for accessing the resource, and NAMESPACE is +the namespace of the resource, or nil if TYPE is not namespaced.") + +(put 'kubed-display-resource-info 'permanent-local t) + +(defun kubed-display-resource-revert (&optional _ _) + "Clear and populate current Kubernetes resource buffer." + (seq-let (type name context namespace) + kubed-display-resource-info + (let ((inhibit-read-only t) + (target (current-buffer))) + (buffer-disable-undo) + (with-temp-buffer + (unless (zerop + (apply + #'process-file + (kubed-kubectl-program) nil t nil "get" + type "--output=yaml" name + (append (when namespace (list "-n" namespace)) + (when context (list "--context" context))))) + (error "Failed to display Kubernetes resource `%s'" name)) + (let ((source (current-buffer))) + (with-current-buffer target + (replace-buffer-contents source) + (set-buffer-modified-p nil) + (buffer-enable-undo))))))) + +(defun kubed-display-resource-in-buffer + (buffer type resource &optional context namespace) + "Display Kubernetes RESOURCE of type TYPE in BUFFER." + (let ((info (list type resource context namespace)) + (dir default-directory)) + (with-current-buffer (get-buffer-create buffer) + (setq-local default-directory dir) + (setq-local kubed-display-resource-info info) + (kubed-display-resource-revert) + (goto-char (point-min)) + (run-hooks 'kubed-yaml-setup-hook) + (kubed-display-resource-mode) + (current-buffer)))) + +(defun kubed-display-resource-short-description + (type resource context namespace) + "Return short string to use as a label for RESOURCE of type TYPE." + (concat type "/" resource + (when namespace (concat "@" namespace)) + (when context (concat "[" context "]")))) + +(defun kubed-namespaced-p (type &optional context) + "Return non-nil if TYPE is a namespaced resource type in context CONTEXT." + (member type (kubed-api-resources context t))) + +(defun kubed--namespace (context &optional prompt-p) + "Return Kubernetes namespace for CONTEXT. + +Non-nil optional argument PROMPT-P says to prompt for a namespace." + (let ((ns (if (equal context (kubed-local-context)) + (kubed-local-namespace) + (kubed-current-namespace context)))) + ;; If CONTEXT is another context that has no configured namespace, + ;; then NS is nil and we must prompt. + (unless ns (setq prompt-p t)) + (if prompt-p + (kubed-read-namespace "Namespace" ns nil context) + ns))) + +;;;###autoload +(defun kubed-display-resource + (type resource context &optional namespace) + "Display Kubernetes RESOURCE of type TYPE in CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCE. With a prefix argument \ +\\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \ +\\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well." + (interactive + (let ((type nil) (context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-display)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless type + (setq type (kubed-read-resource-type "Type of resource to display" + nil context))) + (when (and (null namespace) (kubed-namespaced-p type context)) + (setq namespace (kubed--namespace context current-prefix-arg))) + (list type (kubed-read-resource-name type "Display" nil nil + context namespace) + context namespace))) + (display-buffer + (kubed-display-resource-in-buffer + (concat "*Kubed " + (kubed-display-resource-short-description + type resource context namespace) + "*") + type resource context namespace))) + +(declare-function bookmark-prop-get "bookmark") +(declare-function bookmark-get-front-context-string "bookmark") +(declare-function bookmark-get-rear-context-string "bookmark") +(declare-function bookmark-make-record-default "bookmark") + +;;;###autoload +(defun kubed-display-resource-handle-bookmark (bookmark) + "Display Kubernetes resource according to BOOKMARK." + (require 'bookmark) + (seq-let (type name context namespace) + (bookmark-prop-get bookmark 'resource) + (set-buffer + (kubed-display-resource-in-buffer + (concat "*Kubed " + (kubed-display-resource-short-description + type name context namespace) + "*") + type name context namespace)) + (when-let ((str (bookmark-get-front-context-string bookmark)) + ((search-forward str (point-max) t))) + (goto-char (match-beginning 0))) + (when-let ((str (bookmark-get-rear-context-string bookmark)) + ((search-backward str (point-min) t))) + (goto-char (match-end 0))))) + +(put 'kubed-display-resource-handle-bookmark 'bookmark-handler-type "KubedResource") + +(defun kubed-display-resource-make-bookmark () + "Return bookmark pointing to currently displayed Kubernetes resource." + (require 'bookmark) + (seq-let (type name context namespace) kubed-display-resource-info + (cons + (kubed-display-resource-short-description type name context namespace) + (append + (list + (cons 'handler #'kubed-display-resource-handle-bookmark) + (cons 'resource kubed-display-resource-info)) + (bookmark-make-record-default t))))) + +(defun kubed-display-resource-jump-to-list () + "Jump to line in resources list that corresponds to the displayed resource." + (interactive) + (seq-let (type name context namespace) kubed-display-resource-info + (apply (intern (concat "kubed-list-" type)) context + (when namespace (list namespace))) + (kubed-list-go-to-line name))) + +(defun kubed-display-resource-diff () + "Show diff of current buffer with current state of the displayed resource." + (interactive) + (kubed-diff (current-buffer) nil (nth 2 kubed-display-resource-info))) + +(defun kubed-display-resource-replace () + "Replace displayed Kubernetes resource with current buffer contents." + (interactive) + (let (choice) + (while (= ?d (setq choice + (car (read-multiple-choice + "Replace resource with changes in current buffer?" + '((?y "yes") (?n "no") (?d "diff")))))) + (kubed-display-resource-diff)) + (when (= ?y choice) + (let ((err-buf (get-buffer-create " *kubed-replace*"))) + (with-current-buffer err-buf (erase-buffer)) + (let ((tmpfile (make-temp-file "kubed"))) + (unwind-protect + (progn + (write-region (point-min) (point-max) tmpfile) + (unless (zerop (process-file (kubed-kubectl-program) + tmpfile err-buf nil + "replace" "-f" "-")) + (display-buffer err-buf) + (user-error "`kubectl replace' failed!"))) + (delete-file tmpfile)))) + (message "Replaced Kubernetes resource with changes in current buffer.") + (revert-buffer)))) + +(defun kubed-display-resource-p (_symbol buffer) + "Return non-nil if `kubed-display-resource-mode' is enabled in BUFFER. + +The first argument, SYMBOL, is ignored. You can use this function as +the `completion-predicate' property of commands that you define that +should only be available in buffers that display Kubernetes resources." + (buffer-local-value 'kubed-display-resource-mode buffer)) + +(dolist (cmd '(kubed-display-resource-jump-to-list + kubed-display-resource-diff + kubed-display-resource-replace)) + (put cmd 'completion-predicate #'kubed-display-resource-p)) + +(defvar-keymap kubed-display-resource-mode-map + :doc "Keymap buffers that display Kubernetes resource." + "C-c C-j" #'kubed-display-resource-jump-to-list + "C-c C-=" #'kubed-display-resource-diff + "C-c C-c" #'kubed-display-resource-replace) + +(define-minor-mode kubed-display-resource-mode + "Minor mode for buffers that display a Kubernetes resource." + :interactive nil + :lighter " Kubed" + (when kubed-display-resource-mode + (setq-local + revert-buffer-function #'kubed-display-resource-revert + bookmark-make-record-function #'kubed-display-resource-make-bookmark))) + +(defun kubed-list-filter-lt-operator (v s) + "Return non-nil if S is less than V as a number or as a string." + (let ((l (string-to-number s)) (r (string-to-number v))) + (if (= l r) (string< s v) (< l r)))) + +(defun kubed-list-filter-gt-operator (v s) + "Return non-nil if S is greater than V as a number or as a string." + (let ((l (string-to-number s)) (r (string-to-number v))) + (if (= l r) (string> s v) (> l r)))) + +(defcustom kubed-list-filter-operator-alist + '((= . string=) + (~ . string-match-p) + (< . kubed-list-filter-lt-operator) + (> . kubed-list-filter-gt-operator)) + "Association list of filter operators and functions that implement them. + +Elements of the list are cons cells (OP . FN), where OP is a symbol that +is used as a filter operator and FN is a function that implements OP. +FN takes two arguments, a string STR and a parameter VAL. FN should +return non-nil if STR and VAL are related according to OP: to determine +if a line in which column COL is STR satisfies the filter (OP COL VAL), +Kubed checks if the form (FN VAL STR) evaluates to non-nil." + :type '(alist :key-type (symbol :tag "Operator") :value-type function)) + +(defun kubed-list-interpret-atomic-filter (atom) + "Return function that implements atomic filter ATOM." + (if (eq (car-safe atom) 'quote) + (let ((p (kubed-list-interpret-atomic-filter (cadr atom)))) + (lambda (x) (not (funcall p x)))) + (let* ((column-number (tabulated-list--column-number (symbol-name (nth 1 atom)))) + (value (nth 2 atom)) + (value (if (stringp value) value (prin1-to-string value))) + (op (alist-get (car atom) kubed-list-filter-operator-alist))) + (unless op (user-error "Unknown filter operator `%S'" (car atom))) + (lambda (x) (funcall op value (aref (cadr x) column-number)))))) + +(defvar-local kubed-list-filter nil "Filter in effect in the current buffer.") + +(defun kubed-list-interpret-filter (&optional filter) + "Return function that implements FILTER. + +If FILTER is omitted or nil, it defaults to `kubed-list-filter'." + (let ((conjunction (or filter kubed-list-filter))) + (if (listp (car conjunction)) + (let ((conjuncts + (mapcar (lambda (disjunction) + (if (listp (car disjunction)) + (let ((disjuncts + (mapcar #'kubed-list-interpret-atomic-filter + disjunction))) + (lambda (entry) + (catch 'keep-it + (dolist (pred disjuncts) + (when (funcall pred entry) + (throw 'keep-it t))) + nil))) + ;; Single atomic disjunct. + (kubed-list-interpret-atomic-filter disjunction))) + (or conjunction kubed-list-filter)))) + (lambda (entry) + (catch 'keep-it + (dolist (pred conjuncts) + (unless (funcall pred entry) + (throw 'keep-it nil))) + t))) + ;; Single atomic conjunct. + (kubed-list-interpret-atomic-filter conjunction)))) + +(defun kubed-list-validate-atomic-filter (atom) + "Return string explaining why ATOM is invalid, or nil if it is valid." + (unless (consp atom) + (throw 'validation-error + (format (substitute-quotes + "Invalid atomic filter `%S', must be a list") + atom))) + (if (eq (car-safe atom) 'quote) + (kubed-list-validate-atomic-filter (cadr atom)) + (unless (length= atom 3) + (throw 'validation-error + (format (substitute-quotes + "Invalid atomic filter `%S', must have three elements") + atom))) + (unless (assq (car atom) kubed-list-filter-operator-alist) + (throw 'validation-error + (format (substitute-quotes + "No operator `%S' in `kubed-list-filter-operator-alist'") + (car atom)))) + (unless (ignore-errors + (tabulated-list--column-number (symbol-name (nth 1 atom)))) + (throw 'validation-error (format (substitute-quotes + "Invalid column name `%S'") + (nth 1 atom)))))) + +(defun kubed-list-validate-filter (filter) + "Return string explaining why FILTER is invalid, or nil if it is valid." + (catch 'validation-error + (if (listp (car-safe filter)) + (dolist (disjunction filter) + (if (and (consp disjunction) (listp (car disjunction))) + (dolist (disjunct disjunction) + (kubed-list-validate-atomic-filter disjunct)) + (kubed-list-validate-atomic-filter disjunction))) + (kubed-list-validate-atomic-filter filter)))) + +(defvar-local kubed-list-filter-history-variable nil + "History list variable to use for filter history in the current buffer.") + +(defvar-local kubed--list-read-filter-target-buffer nil + "Resource list buffer for which this minibuffer is reading a filter.") + +(defvar-local kubed-list-type nil) +(defvar-local kubed-list-context nil) +(defvar-local kubed-list-namespace nil) + +(defvar-local kubed-list-transient-extra-suffixes nil + "List of transient suffixes for the type of resources in current buffer.") + +(defsubst kubed--event-point (event) + "Return buffer position of EVENT." + (posn-point (event-start event))) + +(defun kubed-list-go-to-line (id) + "Go to beginning of table line with ID." + (let ((proc (alist-get 'process + (kubed--alist (file-remote-p default-directory) + kubed-list-type + kubed-list-context + kubed-list-namespace))) + (pos nil)) + (save-excursion + ;; Wait for refresh to finish, if currently underway. + (while (process-live-p proc) (accept-process-output proc 1)) + (goto-char (point-min)) + (while (not (or pos (eobp))) + (if (equal id (tabulated-list-get-id)) + (setq pos (point)) + (forward-line)))) + (goto-char pos))) + +(defun kubed-list-try-read-filter () + "Try to read a resource list filter in the minibuffer. + +Exit the minibuffer if successful, else report the error and move point +to the location of the error. If point is not already at the location +of the error, push a mark before moving point." + (interactive "" minibuffer-mode) + (let* ((prompt-end (minibuffer-prompt-end)) + (contents (minibuffer-contents)) + (error-point nil) (error-message nil) (form nil) (inval nil)) + (with-temp-buffer + (condition-case err + (progn + ;; FIXME: There is a small edge case here that could get + ;; better treatment: when `contents' ends with " ?", it + ;; escapes the terminating closing parenthesis and leads us + ;; to incorrectly report the input as incomplete. + (insert "(" contents ")") + (goto-char (point-min)) + (setq form (read (current-buffer)))) + (error (setq error-point (+ prompt-end (1- (point))) + error-message err)))) + (cond + (error-point + (unless (= (point) error-point) (push-mark)) + (goto-char error-point) + (minibuffer-message (error-message-string error-message))) + ((setq inval (with-current-buffer kubed--list-read-filter-target-buffer + (kubed-list-validate-filter form))) + (minibuffer-message inval)) + (t (exit-minibuffer))))) + +(defvar-keymap kubed-list-read-filter-map + :parent minibuffer-local-map + "TAB" #'completion-at-point + "M-?" #'completion-help-at-point + " " #'kubed-list-try-read-filter) + +(defun kubed-list-read-filter (prompt) + "Prompt with PROMPT for a filter for the current buffer." + (let* ((buf (current-buffer)) + (cols (seq-map #'car tabulated-list-format)) + (vals (let ((tmp nil)) + (dolist (ent (alist-get 'resources + (kubed--alist (file-remote-p default-directory) + kubed-list-type + kubed-list-context + kubed-list-namespace))) + (let ((i 0)) + (dolist (col cols) + (push (aref (cadr ent) i) + (alist-get col tmp nil nil #'string=)) + (setq i (1+ i))))) + (mapcar #'delete-dups tmp))) + (filter + (minibuffer-with-setup-hook + (lambda () + (set-syntax-table emacs-lisp-mode-syntax-table) + (setq-local kubed--list-read-filter-target-buffer buf) + (add-hook + 'completion-at-point-functions + (lambda () + (let ((cont (buffer-substring + (minibuffer-prompt-end) (point))) + (bounds (or (bounds-of-thing-at-point 'symbol) + (cons (point) (point))))) + (with-temp-buffer + (set-syntax-table emacs-lisp-mode-syntax-table) + (insert "(" cont) + (when-let ((fn-argi (elisp--fnsym-in-current-sexp)) + (argi (cadr fn-argi))) + (if (= argi 0) + ;; Complete operators. + (list + (car bounds) (cdr bounds) + (mapcar #'car kubed-list-filter-operator-alist)) + (when (car fn-argi) + (cond + ((= argi 1) + ;; Complete column names. + (list (car bounds) (cdr bounds) cols)) + ((= argi 2) + ;; Complete column values. + (when-let ((beg (nth 1 (syntax-ppss))) + ;; Grab preceding symbol. + (col (save-excursion + (goto-char beg) + (forward-char 1) + (forward-sexp 2) + (thing-at-point 'symbol)))) + (list (car bounds) (cdr bounds) + (alist-get col vals + nil nil #'string=))))))))))) + nil t)) + (read-from-minibuffer + (format-prompt prompt "disable") + (mapconcat #'prin1-to-string kubed-list-filter " ") + kubed-list-read-filter-map nil + kubed-list-filter-history-variable "")))) + (car (ignore-errors (read-from-string (format "(%s)" filter)))))) + +(defun kubed-list-set-filter (filter) + "Set the filter of the current buffer to FILTER. + +FILTER determines which resources to keep. FILTER can be an atomic +filter, which is a list (OP COL VAL), where OP is an operator defined in +`kubed-list-filter-operator-alist' (which see), COL is a symbol whose +name is a column name, and VAL is a string or an object whose printed +representation is compared to the value of the column COL according to +OP. For example, the atomic filter (= Name foobar) keeps only resources +whose name is \"foobar\". (= Name \"foobar\") does exactly the same. +To negate an atomic filter, quote it. E.g. use \\='(~ Namespace kube) +to hide all resources in namespaces whose name contains \"kube\". + +FILTER can also be a list of sub-filters (SUB1 SUB2 ...) where each +sub-filter is either an atomic filter or a list of atomic filters. If a +sub-filter is a list of atomic filters, then that sub-filter denotes the +disjunction of those atomic filters. FILTER denotes the conjunction of +the sub-filters. In particular, FILTER nil denotes the empty +conjunction which is always true (keeps all resources). + +More examples: + +- `((= Name foobar) (~ Namespace kube))': keep only resources named + \"foobar\" in namespaces that contain \"kube\". +- `(((= Name foobar) (~ Namespace kube)))': keep resources that are + either named \"foobar\" or in a namespace that contains \"kube\". +- `(((= Name foobar) (~ Namespace kube)) \\='(~ Starttime 2024-07))': + keep only resources that are either named \"foobar\" or in a namespace + that contains \"kube\", and were not started during July 2024. + +Interactively, prompt for FILTER sans the outermost set of parenthesis. +For example, enter \"= Name foobar\" in the minibuffer to specify the +atomic FILTER (= Name foobar). + +See also Info node \"(kubed) List Filter\"." + (interactive (list (kubed-list-read-filter "Set filter")) kubed-list-mode) + (when-let ((validation-error (kubed-list-validate-filter filter))) + (user-error validation-error)) + (setq-local kubed-list-filter filter) + (revert-buffer)) + +(defun kubed-list-mark-for-deletion () + "Mark Kubernetes resource at point for deletion." + (interactive "" kubed-list-mode) + (tabulated-list-put-tag (propertize "D" 'help-echo "Marked for deletion") t)) + +(defun kubed-list-unmark () + "Remove mark from Kubernetes resource at point." + (interactive "" kubed-list-mode) + (tabulated-list-put-tag " " t)) + +(defun kubed-list-previous-column (&optional n) + "Move backward N columns. + +Interactively, N is the numeric value of the prefix argument, defaulting +to 1." + (interactive "p" kubed-list-mode) + (kubed-list-next-column (- n))) + +(defun kubed-list-next-column (&optional n) + "Move forward N columns. + +Interactively, N is the numeric value of the prefix argument, defaulting +to 1." + (interactive "p" kubed-list-mode) + (let ((next (point)) + (times (abs (or n 1))) + (dir-fn (if (< 0 n) + #'next-single-property-change + #'previous-single-property-change))) + (dotimes (_ times) + (setq next (funcall dir-fn next 'tabulated-list-column-name)) + (when (equal (char-after next) ?\n) + ;; At line boundary, go to first/last column of next line. + (setq next (funcall dir-fn next 'tabulated-list-column-name))) + (unless next (user-error "End of table"))) + (goto-char next))) + +(defun kubed-list-copy-as-kill (click) + "Copy name of Kubernetes resource at CLICK into the kill ring." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((ent (tabulated-list-get-entry (kubed--event-point click))) + (new (aref ent 0))) + (progn + (kill-new new) + (message "Copied resource name `%s'" new)) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-context-menu (menu click) + "Extend MENU with common actions on Kubernetes resource at CLICK." + (when (tabulated-list-get-entry (kubed--event-point click)) + (define-key menu [kubed-list-select-resource] + '(menu-item "Select" kubed-list-select-resource)) + (define-key menu [kubed-list-display-resource] + '(menu-item "Display" kubed-list-display-resource)) + (define-key menu [kubed-list-delete] + '(menu-item "Delete" kubed-list-delete)) + (define-key menu [kubed-list-patch] + '(menu-item "Patch" kubed-list-patch)) + (define-key menu [kubed-list-edit] + '(menu-item "Edit" kubed-list-edit)) + (define-key menu [kubed-list-kubectl-command] + '(menu-item "Execute `kubectl' command" kubed-list-kubectl-command)) + (define-key menu [kubed-list-copy-as-kill] + '(menu-item "Copy name" kubed-list-copy-as-kill))) + menu) + +(defun kubed-list-update (&optional quiet) + "Update list of Kubernetes resources. + +If optional argument QUIET is non-nil, do not emit a message when +starting to update. Display a message when the update is done +regardless of QUIET." + (interactive "" kubed-list-mode) + (kubed-update kubed-list-type kubed-list-context kubed-list-namespace) + (force-mode-line-update) + (unless quiet (minibuffer-message (format "Updating Kubernetes %S..." kubed-list-type)))) + +(defun kubed-list-delete-marked () + "Delete marked Kubernetes resources." + (interactive "" kubed-list-mode) + (let (delete-list) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (when (eq (char-after) ?D) + (push (tabulated-list-get-id) delete-list)) + (forward-line))) + (if delete-list + (when (y-or-n-p (format "Delete %d marked Kubernetes resources?" + (length delete-list))) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (when (member (tabulated-list-get-id) delete-list) + (tabulated-list-put-tag + (propertize "K" 'help-echo "Deletion in progress"))) + (forward-line))) + (let ((errb (generate-new-buffer " *kubed-list-delete-marked-stderr*")) + (buf (current-buffer))) + (make-process + :name "*kubed-list-delete-marked*" + :stderr errb + :file-handler t + :command (cons (kubed-kubectl-program) + (append + (when kubed-list-context + (list "--context" kubed-list-context)) + (when kubed-list-namespace + (list "--namespace" kubed-list-namespace)) + (list "delete" kubed-list-type) + delete-list)) + :sentinel (lambda (_proc status) + (cond + ((string= status "finished\n") + (message (format "Deleted %d marked Kubernetes resources." + (length delete-list))) + (when (buffer-live-p buf) + (with-current-buffer buf + (kubed-list-update t)))) + ((string= status "exited abnormally with code 1\n") + (with-current-buffer errb + (goto-char (point-max)) + (insert "\n" status)) + (display-buffer errb))))))) + (user-error "No Kubernetes resources marked for deletion")))) + +(defun kubed-list-display-resource (click) + "Display Kubernetes resource at CLICK in another window." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (kubed-display-resource + kubed-list-type resource kubed-list-context kubed-list-namespace) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-select-resource (click) + "Display Kubernetes resource at CLICK in current window." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (switch-to-buffer + (kubed-display-resource-in-buffer + (concat "*Kubed " + (kubed-display-resource-short-description + kubed-list-type resource kubed-list-context kubed-list-namespace) + "*") + kubed-list-type resource kubed-list-context kubed-list-namespace)) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-select-resource-other-window (click) + "Display Kubernetes resource at CLICK in other window and select that window." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (switch-to-buffer-other-window + (kubed-display-resource-in-buffer + (concat "*Kubed " + (kubed-display-resource-short-description + kubed-list-type resource kubed-list-context kubed-list-namespace) + "*") + kubed-list-type resource kubed-list-context kubed-list-namespace)) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-delete (click) + "Delete Kubernetes resource at CLICK." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (when (y-or-n-p (format "Delete `%s'?" resource)) + (kubed-delete-resources kubed-list-type (list resource) + kubed-list-context kubed-list-namespace)) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-patch (click) + "Patch Kubernetes resource at CLICK." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (kubed-patch kubed-list-type resource + (kubed-read-patch) kubed-list-context kubed-list-namespace) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-edit (click) + "Edit Kubernetes resource at CLICK." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (kubed-edit-resource kubed-list-type resource + kubed-list-context kubed-list-namespace) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-kubectl-command (click) + "Use Kubernetes resource at CLICK as argument for `kubectl' command." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (kubed-kubectl-command + (kubed-read-kubectl-command + "Execute command: " + (cons (concat + " " + (when kubed-list-namespace (concat "-n " kubed-list-namespace " ")) + (when kubed-list-context (concat "--context " kubed-list-context " ")) + kubed-list-type " " resource) + ;; Put point after "kubectl ". + 0))) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-logs (click) + "Show logs for Kubernetes resource at CLICK." + (interactive (list last-nonmenu-event) kubed-list-mode) + (if-let ((resource (tabulated-list-get-id (kubed--event-point click)))) + (let ((lines (unless (zerop kubed-logs-tail-lines) kubed-logs-tail-lines))) + (kubed-logs kubed-list-type resource kubed-list-context kubed-list-namespace + t kubed-logs-follow nil t nil lines)) + (user-error "No Kubernetes resource at point"))) + +(defun kubed-list-create (definition &optional kind) + "Create Kubernetes resource of kind KIND from definition file DEFINITION." + (interactive (list (kubed-read-resource-definition-file-name)) kubed-list-mode) + (kubed-create definition kind kubed-list-context) + (kubed-list-update t)) + +(defun kubed-list-column-number-at-point () + "Return table column number at point." + (let ((start (current-column)) + (nb-cols (1- (length tabulated-list-format))) + (col-nb 0) + (total-width tabulated-list-padding) + (found nil)) + (while (and (not found) (< col-nb nb-cols)) + (if (>= start + (setq total-width + (+ total-width + (cadr (aref tabulated-list-format col-nb)) + (or (plist-get (nthcdr 3 (aref tabulated-list-format + col-nb)) + :pad-right) + 1)))) + (setq col-nb (1+ col-nb)) + (setq found t))) + col-nb)) + +(defun kubed-list-fit-column-width-to-content (n) + "Fit width of Nth table column to its content. + +If N is negative, fit all columns. Interactively, N is the column +number at point, or the numeric prefix argument if you provide one." + (interactive + (list (if current-prefix-arg + (prefix-numeric-value current-prefix-arg) + (kubed-list-column-number-at-point))) + kubed-list-mode) + (if (< n 0) + ;; Fit all columns. + (let* ((num-cols (length tabulated-list-format)) + (widths (apply #'vector (seq-map + ;; +2 to make room for sorting icon. + (lambda (col) (+ 2 (length (car col)))) + tabulated-list-format)))) + (save-excursion + (goto-char (point-min)) + (while-let ((entry (tabulated-list-get-entry))) + (dotimes (i num-cols) + (aset widths i (max (aref widths i) (length (aref entry i))))) + (forward-line))) + (setq tabulated-list-format (copy-tree tabulated-list-format t)) + (dotimes (i num-cols) + (setf (cadr (aref tabulated-list-format i)) + (1+ (aref widths i))))) + ;; Fit Nth column. + (let* ((width (+ 2 (length (car (aref tabulated-list-format n)))))) + (save-excursion + (goto-char (point-min)) + (while-let ((entry (tabulated-list-get-entry))) + (setq width (max width (length (aref entry n)))) + (forward-line))) + (setq tabulated-list-format (copy-tree tabulated-list-format t)) + (setf (cadr (aref tabulated-list-format n)) (1+ width)))) + (tabulated-list-print t) + (tabulated-list-init-header)) + +(declare-function kubed-transient "kubed-transient" ()) +(declare-function kubed-list-transient "kubed-transient" ()) +(declare-function kubed-transient-logs-for-pod "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-deployment "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-statefulset "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-replicaset "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-daemonset "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-job "kubed-transient" (val)) +(declare-function kubed-transient-logs-for-service "kubed-transient" (val)) + +(defvar-keymap kubed-list-mode-map + :doc "Common keymap for Kubernetes resource list buffers." + "RET" #'kubed-list-select-resource + "o" #'kubed-list-select-resource-other-window + "C-o" #'kubed-list-display-resource + "D" #'kubed-list-delete + "P" #'kubed-list-patch + "x" #'kubed-list-delete-marked + "e" #'kubed-list-edit + "!" #'kubed-list-kubectl-command + "g" #'kubed-list-update + "/" #'kubed-list-set-filter + "|" #'kubed-list-fit-column-width-to-content + "d" #'kubed-list-mark-for-deletion + "u" #'kubed-list-unmark + "w" #'kubed-list-copy-as-kill + "C-i" #'kubed-list-next-column + "TAB" #'kubed-list-next-column + "C-S-i" #'kubed-list-previous-column + "S-TAB" #'kubed-list-previous-column + "" #'kubed-list-previous-column + "+" #'kubed-list-create + "?" #'kubed-list-transient) + +(defun kubed-list-entries () + "`tabulated-list-entries' function for `kubed-list-mode'." + (let ((pred (kubed-list-interpret-filter)) + (ents nil)) + (dolist (ent (alist-get 'resources (kubed--alist (file-remote-p default-directory) + kubed-list-type + kubed-list-context + kubed-list-namespace))) + (when (funcall pred ent) (push ent ents))) + (reverse ents))) + +;;;###autoload +(defun kubed-list-handle-bookmark (bookmark) + "Display Kubernetes resource according to BOOKMARK." + (require 'bookmark) + (let* ((type (bookmark-prop-get bookmark 'type)) + (context (bookmark-prop-get bookmark 'context)) + (namespace (bookmark-prop-get bookmark 'namespace)) + (current (bookmark-prop-get bookmark 'current)) + (buff-fn (intern (format "kubed-%s-buffer" type))) + (buff (apply buff-fn context (when namespace (list namespace))))) + (set-buffer buff) + (when current (kubed-list-go-to-line current)))) + +(put 'kubed-list-handle-bookmark 'bookmark-handler-type "KubedList") + +(defun kubed-list-make-bookmark () + "Return bookmark pointing to currently displayed Kubernetes resource." + (require 'bookmark) + (cons + (concat kubed-list-type + (when kubed-list-namespace (concat "@" kubed-list-namespace)) + (when kubed-list-context (concat "[" kubed-list-context "]"))) + (append + (list + (cons 'handler #'kubed-list-handle-bookmark) + (cons 'filter kubed-list-filter) + (cons 'type kubed-list-type) + (cons 'context kubed-list-context) + (cons 'current (tabulated-list-get-id)) + (cons 'namespace kubed-list-namespace))))) + +(defun kubed-list-revert (&rest _) + "Revert the current Kubernetes resources list buffer. + +This is the `revert-buffer-function' for `kubed-list-mode' and its +derivatives. This function does not fetch new data from Kubernetes, it +only (re)displays the existing data." + (let (marks) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (unless (eq (char-after) ?\s) + (push (cons (tabulated-list-get-id) + ;; Preserve mark text properties. + (buffer-substring (point) (1+ (point)))) + marks)) + (forward-line))) + (tabulated-list-revert) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let ((id (tabulated-list-get-id))) + (when-let ((mark (alist-get id marks nil nil #'equal))) + (tabulated-list-put-tag mark))) + (forward-line))))) + +(define-derived-mode kubed-list-mode tabulated-list-mode "Kubernetes Resources" + "Major mode for listing Kubernetes resources. + +Modes for specific resource types, such as `kubed-pods-mode', use this +mode as their parent." + :interactive nil + (setq-local truncate-string-ellipsis (propertize ">" 'face 'shadow) + tabulated-list-entries #'kubed-list-entries + bookmark-make-record-function #'kubed-list-make-bookmark + revert-buffer-function #'kubed-list-revert) + (add-hook 'context-menu-functions #'kubed-list-context-menu nil t)) + +;;;###autoload +(defun kubed-delete-resources (type resources context &optional namespace) + "Delete Kubernetes RESOURCES of type TYPE in context CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCES. With a prefix argument \ +\\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \ +\\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well." + (interactive + (let ((type nil) (context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-delete)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless type + (setq type (kubed-read-resource-type "Type of resource to delete" + nil context))) + (when (and (null namespace) (kubed-namespaced-p type context)) + (setq namespace (kubed--namespace context current-prefix-arg))) + (list type (kubed-read-resource-name type "Delete" nil t + context namespace) + context namespace))) + (unless resources (user-error "You didn't specify %s to delete" type)) + (message (format "Deleting Kubernetes %s `%s'..." + type (string-join resources "', `"))) + (if (zerop (apply #'process-file + (kubed-kubectl-program) nil nil nil + "delete" type + (append (when namespace (list "-n" namespace)) + (when context (list "--context" context)) + resources))) + (message (format "Deleting Kubernetes %s `%s'... Done." + type (string-join resources "', `"))) + (error (format "Failed to delete Kubernetes %s `%s'" + type (string-join resources "', `"))))) + +;;;###autoload +(defun kubed-edit-resource (type resource context &optional namespace) + "Edit Kubernetes RESOURCE of type TYPE in context CONTEXT. + +For namespaced resource types, NAMESPACE is the namespace of RESOURCE. + +Interactively, use the current context and namespace by default, and +prompt for TYPE and RESOURCES. With a prefix argument \ +\\[universal-argument], +prompt for NAMESPACE. With a double prefix argument \ +\\[universal-argument] \\[universal-argument], +prompt for CONTEXT as well." + (interactive + (let ((type nil) (context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-edit)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless type + (setq type (kubed-read-resource-type "Type of resource to edit" + nil context))) + (when (and (null namespace) (kubed-namespaced-p type context)) + (setq namespace (kubed--namespace context current-prefix-arg))) + (list type (kubed-read-resource-name type "Edit" nil nil + context namespace) + context namespace))) + (unless (bound-and-true-p server-process) (server-start)) + (let ((process-environment + (cons (if (boundp 'emacsclient-program-name) + (concat "KUBE_EDITOR=" emacsclient-program-name) + "KUBE_EDITOR=emacsclient") + process-environment))) + (apply #'start-file-process + (format "*kubed-%S-edit*" type) nil + (kubed-kubectl-program) "edit" type resource + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context)))))) + +(defcustom kubed-list-mode-line-format + '(:eval (cond + ((process-live-p + (alist-get 'process + (kubed--alist (file-remote-p default-directory) + kubed-list-type + kubed-list-context + kubed-list-namespace))) + (propertize "[...]" 'help-echo "Updating...")) + (kubed-list-filter + (propertize + (concat "[" (mapconcat #'prin1-to-string kubed-list-filter " ") "]") + 'help-echo "Current filter")))) + "Mode line construct for indicating status of Kubernetes resources list." + :type 'sexp + :risky t) + +;;;###autoload +(defmacro kubed-define-resource (resource &optional properties &rest commands) + "Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS. + +RESOURCE is a symbol corresponding to a Kubernetes resource type, such +as `pod' or `service'. This macro defines the following commands for +interacting with Kubernetes RESOURCEs: + +- `kubed-display-RESOURCE': prompt for a RESOURCE and display its + description in YAML format. See also `kubed-yaml-setup-hook'. +- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it. +- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it. +- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the + current namespace. The RESOURCEs list buffer uses a dedicated major + mode, `kubed-RESOURCEs-mode', which is also defined by this macro. +- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file. +- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs. + +This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map', +with bindings for the above commands. + +PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS) +that specify properties of RESOURCEs. PROP is the name of the property, +as a symbol; JSON-PATH is a JSONPath expression that evaluates to the +value of PROP when applied to the JSON representation of a RESOURCE. +WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted. WIDTH is +used as the default width of the column corresponding to PROP in +RESOURCEs list buffers; SORT is sort predicate, a function that takes +two values of PROP as strings and returns non-nil if the first should +sort before the second; FORMAT is a function that takes a value of PROP +and formats it. If you provide a FORMAT function and a SORT function, +then the SORT function gets the formatted values (the output of the +FORMAT function), not the original values. If you want to sort based on +the unformatted original values, you can store them as text properties +in your FORMAT function and access them in your SORT function. + +ATTRS is a plist of additional attributes of the PROP column, see +`tabulated-list-format' for available attributes. + +For example, if PROPERTIES is (phase \".status.phase\" 10) that means +that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose +values are typically 10 columns wide. The first property in PROPERTIES +is used to annotate completion candidates when prompting for a RESOURCE. + +COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that +define commands for RESOURCE list buffers. COMMAND is a symbol +specifying the suffix of the command name, the full name of the command +is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is +either a string that specifies a key sequence to bind to the command in +`kubed-RESOURCEs-mode-map', or nil if the command should not be bound; +DOC-PREFIX is a string used to construct the docstring of the command, +this macro appends the string \" Kubernetes RESOURCE at point.\" to it +to obtain the final docstring; lastly, BODY is the body the command. +Within BODY, the variable RESOURCE is let-bound to the name of the +RESOURCE at point. For example, if RESOURCE is `pod', the following +COMMANDS element defines a command `kubed-pods-frob' and binds it to the +key \"f\" in `kubed-pods-mode-map': + + (frob \"f\" \"Frobnicate\" + (message \"Preparing...\") + (frobnicate-pod pod) + (message \"Done.\")) + +By default, this macro assumes that RESOURCE is namespaced. To define a +namespaceless resource type, put `:namespaced nil' before COMMANDS: + + (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil + CMD1 + CMD2 + ...) + +Other keyword arguments that go between PROPERTIES and COMMANDS are: + +- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the + resource creation command, `kubed-create-RESOURCE'. ARGLIST, + DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'. +- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the + prefix keymap `kubed-RESOURCE-prefix-map' and the + `kubed-RESOURCE-menu-map' menu. Each element (KEY LABEL DEFINITION) + says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to + add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL. +- `:plural PLURAL': specify plural form of RESOURCE, as a symbol. If + you omit this keyword argument, the plural form defaults to RESOURCE + followed by \"s\". +- `:logs t': generate `kubed-logs-for-RESOURCE' command. +- `:suffixes (SUFFIX...)': add type-specific transient suffixes to + `kubed-list-transient'." + (declare (indent 2)) + (let ((plrl-var (intern (format "%Ss" resource))) + (read-fun (intern (format "kubed-read-%S" resource))) + (dsp-name (intern (format "kubed-display-%S" resource))) + (edt-name (intern (format "kubed-edit-%S" resource))) + (crt-name (intern (format "kubed-create-%S" resource))) + (map-name (intern (format "kubed-%S-prefix-map" resource))) + (menu-map (intern (format "kubed-%S-menu-map" resource))) + (logs-cmd (intern (format "kubed-logs-for-%S" resource))) + (logs-trs (intern (format "kubed-transient-logs-for-%S" resource))) + (namespaced t) (logs nil) + (keyword nil) + frmt-var buff-fun list-cmd expl-cmd dlt-name mod-name + ctxt-fun crt-spec prf-keys hist-var trs-cols) + + ;; Process keyword arguments. + (while (keywordp (car commands)) + (setq keyword (pop commands)) + (cond + ((eq keyword :namespaced) (setq namespaced (pop commands))) + ((eq keyword :logs) (setq logs (pop commands))) + ((eq keyword :create) (setq crt-spec (pop commands))) + ((eq keyword :prefix) (setq prf-keys (pop commands))) + ((eq keyword :plural) (setq plrl-var (pop commands))) + ((eq keyword :suffixes) (setq trs-cols (pop commands))) + ;; FIXME: Add error for unknown keywords. + (t (pop commands)))) + + (setq frmt-var (intern (format "kubed-%S-columns" plrl-var)) + hist-var (intern (format "kubed-%S-history" plrl-var)) + buff-fun (intern (format "kubed-%S-buffer" plrl-var)) + list-cmd (intern (format "kubed-list-%S" plrl-var)) + expl-cmd (intern (format "kubed-explain-%S" plrl-var)) + dlt-name (intern (format "kubed-delete-%S" plrl-var)) + mod-name (intern (format "kubed-%S-mode" plrl-var)) + ctxt-fun (intern (format "kubed-%S-context-menu" plrl-var))) + + (when logs (push `("L" "Show Logs" ,logs-cmd) prf-keys)) + + ;; Generate code. + `(progn + (setf (alist-get ,(symbol-name plrl-var) kubed--columns nil nil #'string=) + (list + '("NAME:.metadata.name") + ,@(mapcar (lambda (p) + `(cons ,(concat (upcase (symbol-name (car p))) + ":" + (cadr p)) + ,(nth 4 p))) + properties))) + + (defvar ,hist-var nil + ,(format "History list for `%S'." read-fun)) + + (defun ,read-fun (prompt &optional default multi context + . ,(when namespaced '(namespace))) + ,(format "Prompt with PROMPT for a Kubernetes %S name. + +Optional argument DEFAULT is the minibuffer default argument. + +Non-nil optional argument MULTI says to read and return a list +of %S, instead of just one." resource plrl-var) + (kubed-read-resource-name ,(symbol-name plrl-var) prompt default multi context . ,(when namespaced '(namespace)))) + + (defun ,dsp-name (,resource &optional context . ,(when namespaced '(namespace))) + ,(if namespaced + (format "Display Kubernetes %S %s in CONTEXT and NAMESPACE. + +Interactively, use the current context and namespace by default. With a +prefix argument \\[universal-argument], prompt for NAMESPACE. With a +double prefix argument \\[universal-argument] \\[universal-argument], \ +prompt for CONTEXT as well." resource (upcase (symbol-name resource))) + (format "Display Kubernetes %S %s in context CONTEXT. + +Interactively, use the current context. With a prefix argument +\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource)))) + (interactive + ,(if namespaced + `(let ((context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-display)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (,read-fun "Display" nil nil context namespace) context namespace)) + `(let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-display)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (list (,read-fun "Display" nil nil context) context)))) + (let ((context (or context (kubed-local-context)))) + (kubed-display-resource + ,(symbol-name plrl-var) ,resource context + . ,(when namespaced '((or namespace (kubed--namespace context))))))) + + (defun ,edt-name (,resource &optional context . ,(when namespaced '(namespace))) + ,(if namespaced + (format "Edit Kubernetes %S %s in CONTEXT and NAMESPACE. + +Interactively, use the current context and namespace by default. With a +prefix argument \\[universal-argument], prompt for NAMESPACE. With a +double prefix argument \\[universal-argument] \\[universal-argument], \ +prompt for CONTEXT as well." resource (upcase (symbol-name resource))) + (format "Edit Kubernetes %S %s in context CONTEXT. + +Interactively, use the current context. With a prefix argument +\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource)))) + (interactive + ,(if namespaced + `(let ((context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-edit)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (,read-fun "Edit" nil nil context namespace) context namespace)) + `(let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-edit)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (list (,read-fun "Edit" nil nil context) context)))) + (let ((context (or context (kubed-local-context)))) + (kubed-edit-resource + ,(symbol-name plrl-var) ,resource context + . ,(when namespaced '((or namespace (kubed--namespace context))))))) + + (defun ,dlt-name (,plrl-var &optional context + . ,(when namespaced '(namespace))) + ,(if namespaced + (format "Delete Kubernetes %S %s in CONTEXT and NAMESPACE. + +Interactively, use the current context and namespace by default. With a +prefix argument \\[universal-argument], prompt for NAMESPACE. With a +double prefix argument \\[universal-argument] \\[universal-argument], \ +prompt for CONTEXT as well." plrl-var (upcase (symbol-name plrl-var))) + (format "Delete Kubernetes %S %s in context CONTEXT. + +Interactively, use the current context. With a prefix argument +\\[universal-argument], prompt for CONTEXT." plrl-var (upcase (symbol-name plrl-var)))) + (interactive + ,(if namespaced + `(let ((context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-delete)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (,read-fun "Delete" nil t context namespace) context namespace)) + `(let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-delete)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (list (,read-fun "Delete" nil t context) context)))) + (unless ,plrl-var + (user-error ,(format "You didn't specify %S to delete" plrl-var))) + (let ((context (or context (kubed-local-context)))) + (kubed-delete-resources + ,(symbol-name plrl-var) ,plrl-var context + . ,(when namespaced '((or namespace (kubed--namespace context))))))) + + ,(if crt-spec `(defun ,crt-name . ,crt-spec) + `(defun ,crt-name (definition &optional context) + ,(format "Create Kubernetes %s from file DEFINITION in CONTEXT. + +Interactively, prompt for DEFINITION and use the current context. With +a prefix argument \\[universal-argument], prompt for CONTEXT too." + (symbol-name resource)) + (interactive + (let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (list (kubed-read-resource-definition-file-name ,(symbol-name resource)) + context))) + (kubed-create definition ,(symbol-name resource) context) + (kubed-update ,(symbol-name plrl-var) context))) + + ,@(when logs + `((defun ,logs-cmd + ( ,resource &optional context namespace + container follow limit prefix since tail timestamps) + ,(format "Show logs for Kubernetes %S %s." + resource (upcase (symbol-name resource))) + (interactive + (let ( ,resource context namespace + container follow limit prefix since tail timestamps) + (dolist (arg (kubed-transient-args + ',logs-trs)) + (cond + ((string-match ,(format "%S/\\(.+\\)" plrl-var) arg) + (setq ,resource (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--limit-bytes=\\(.+\\)" arg) + (setq limit (string-to-number (match-string 1 arg)))) + ((string-match "--tail=\\(.+\\)" arg) + (setq tail (string-to-number (match-string 1 arg)))) + ((string-match "--since-time=\\(.+\\)" arg) + (setq since (match-string 1 arg))) + ((equal "--all-containers" arg) (setq container t)) + ((equal "--follow" arg) (setq follow t)) + ((equal "--prefix" arg) (setq prefix t)) + ((equal "--timestamps" arg) (setq timestamps t)))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (unless ,resource + (setq ,resource (,read-fun "Show logs for" + (and (equal context kubed-list-context) + (equal namespace kubed-list-namespace) + (equal ,(symbol-name plrl-var) kubed-list-type) + (tabulated-list-get-id (kubed--event-point last-nonmenu-event))) + nil context namespace))) + (list ,resource context namespace + ,(if (eq resource 'pod) + '(or container + (kubed-read-container pod "Container" t + context namespace)) + 'container) + (or follow + (unless (bound-and-true-p transient-current-command) + kubed-logs-follow)) + limit prefix since + (or tail + (unless (or (bound-and-true-p transient-current-command) + (zerop kubed-logs-tail-lines)) + kubed-logs-tail-lines)) + timestamps))) + (kubed-logs ,(symbol-name plrl-var) ,resource context namespace container + follow limit prefix since tail timestamps)))) + + ,@(let ((click-var (gensym "click"))) + (mapcar + (pcase-lambda (`(,suffix ,_key ,desc . ,body)) + `(defun ,(intern (format "kubed-%S-%S" plrl-var suffix)) (,click-var) + ,(format "%s Kubernetes %S at point." desc resource) + (interactive (list last-nonmenu-event) ,mod-name) + (if-let ((,resource (tabulated-list-get-id (kubed--event-point ,click-var)))) + (progn ,@body) + (user-error ,(format "No Kubernetes %S at point" resource))))) + commands)) + + (defvar-keymap ,(intern (format "kubed-%S-mode-map" plrl-var)) + :doc ,(format "Keymap for `%S" mod-name) + "+" #',crt-name + ,@(when logs + `("l" #'kubed-list-logs + "L" #',logs-trs)) + ,@(mapcan + (pcase-lambda (`(,suffix ,key ,_desc . ,_body)) + (when key + (list key `#',(intern (format "kubed-%S-%S" plrl-var suffix))))) + commands)) + + (defvar ,frmt-var + ',(let ((i 0) + (res nil)) + (dolist (p properties) + (setq i (1+ i)) + (push + (append + (list (capitalize (symbol-name (car p))) + (caddr p) + (if-let ((sorter (cadddr p))) + `(lambda (l r) + (funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i))) + t)) + (nthcdr 5 p)) + res)) + (reverse res))) + + (defun ,ctxt-fun (menu . ,(if commands '(click) '(_click))) + ,@(when commands + `((when (tabulated-list-get-entry (kubed--event-point click)) + ,@(mapcar + (pcase-lambda (`(,suffix ,_key ,desc . ,_body)) + `(define-key + menu [,(intern (format "kubed-%S-%S" plrl-var suffix))] + (list 'menu-item ,(format "%s this %S" desc resource) + #',(intern (format "kubed-%S-%S" plrl-var suffix))))) + (reverse commands))))) + menu) + + (define-derived-mode ,mod-name kubed-list-mode + '(,(format "Kubernetes %s" (capitalize (symbol-name plrl-var))) + kubed-list-mode-line-format) + ,(format "Major mode for listing Kubernetes %S." plrl-var) + :interactive nil + (setq kubed-list-filter-history-variable + ',(intern (format "kubed-%S-filter-history" plrl-var)) + kubed-list-type ,(symbol-name plrl-var) + ,@(when trs-cols + `(kubed-list-transient-extra-suffixes ',trs-cols)) + tabulated-list-padding 2 + tabulated-list-format (apply #'vector (cons kubed-name-column ,frmt-var))) + (add-hook 'context-menu-functions #',ctxt-fun nil t) + (tabulated-list-init-header)) + + (defun ,buff-fun (context . ,(when namespaced '(namespace))) + (let ((buf-name (format ,(format "*Kubed %S%%s*" plrl-var) + (concat + ,(if namespaced + `(concat "@" namespace "[" context "]") + `(concat "[" context "]")) + (when-let ((host (file-remote-p default-directory))) + (concat " from " host)))))) + (if-let ((buf (get-buffer buf-name))) buf + (with-current-buffer (get-buffer-create buf-name) + (,mod-name) + (setq kubed-list-context context + ,@(when namespaced + '(kubed-list-namespace namespace))) + (kubed-list-update) + (tabulated-list-print) + (current-buffer))))) + + (defun ,list-cmd (context . ,(when namespaced '(namespace))) + ,(if namespaced + (format "List Kubernetes %S in context CONTEXT and namespace NAMESPACE. + +Interactively, use the current context and namespace by default. With a +prefix argument \\[universal-argument], prompt for NAMESPACE. With a +double prefix argument \\[universal-argument] \\[universal-argument], \ +prompt for CONTEXT as well." plrl-var) + (format "List Kubernetes %S in context CONTEXT. + +Interactively, use the current context. With a prefix argument +\\[universal-argument], prompt for CONTEXT." plrl-var)) + (interactive + (let* ((context (kubed-local-context)) + (context (if (equal current-prefix-arg + ,(if namespaced ''(16) ''(4))) + (kubed-read-context "Context" context) + context))) + (list context + . ,(when namespaced '((kubed--namespace context current-prefix-arg)))))) + (pop-to-buffer (,buff-fun context . ,(when namespaced '(namespace))))) + + (defun ,expl-cmd () + ,(format "Show help buffer with explanation about Kubernetes %S." plrl-var) + (interactive) + (kubed-explain ,(symbol-name plrl-var))) + + (defvar-keymap ,map-name + :doc ,(format "Prefix keymap for Kubed %S commands." resource) + :prefix ',map-name + "l" #',list-cmd + "+" #',crt-name + "e" #',edt-name + "d" #',dlt-name + "RET" #',dsp-name + "E" #',expl-cmd + ,@(mapcan + (pcase-lambda (`(,key ,_label ,cmd)) + (list key `#',cmd)) + prf-keys)) + + (defvar-keymap ,menu-map + :doc ,(format "Keymap with Kubernetes %S related menu entries." resource) + :prefix ',menu-map + "" '("List" . ,list-cmd) + "" '("Create" . ,crt-name) + "" '("Edit" . ,edt-name) + "" '("Delete" . ,dlt-name) + "" '("Display" . ,dsp-name) + "" '("Explain Fields" . ,expl-cmd) + ,@(mapcan + (pcase-lambda (`(,key ,label ,cmd)) + (list key `'(,label . ,cmd))) + prf-keys))))) + +(setf + ;; Teach Imenu about `kubed-define-resource'. + (alist-get "KubedResource" lisp-imenu-generic-expression nil nil #'equal) + (list (concat "^\\s-*(kubed-define-resource\\s-+\\(" + lisp-mode-symbol-regexp + "\\)") + 1)) + +(defconst kubed--hex-encoding-table + (let ((vec (make-vector 256 nil))) + (dotimes (byte 256) (aset vec byte (format ".%02X" byte))) vec)) + +(defconst kubed--hex-allowed-chars-table + (let ((vec (make-vector 256 nil))) + (dolist (byte '( ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z + ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z + ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 + ?- ?_)) + (ignore-errors (aset vec byte t))) + vec)) + +(defun kubed--encode-context-name (str) + ;; Adopted from `url-hexify-string'. + (mapconcat (lambda (byte) + (if (aref kubed--hex-allowed-chars-table byte) + (char-to-string byte) + (aref kubed--hex-encoding-table byte))) + (if (multibyte-string-p str) + (encode-coding-string str 'utf-8) + str))) + +(defun kubed-remote-file-name (context namespace pod &optional file-name) + "Return remote FILE-NAME for POD in NAMESPACE and CONTEXT." + (concat (if-let ((host (file-remote-p default-directory))) + (concat (substring host 0 (1- (length host))) "|") + "/") + kubed-tramp-method ":" + (kubed--encode-context-name context) "%" namespace "%" pod + "%" (kubed-read-container pod "Container" t context namespace) + ":" file-name)) + +(declare-function kubed-tramp-context "kubed-tramp" (file-name)) +(declare-function kubed-tramp-namespace "kubed-tramp" (file-name)) +(declare-function kubed-tramp-assert-support "kubed-tramp" ()) + +;;;###autoload (autoload 'kubed-display-pod "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-pod "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-pods "kubed" nil t) +;;;###autoload (autoload 'kubed-list-pods "kubed" nil t) +;;;###autoload (autoload 'kubed-create-pod "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-pod "kubed" nil t) +;;;###autoload (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource pod + ((phase ".status.phase" 10 + nil ; sorting function + (lambda (ph) + (if-let ((face (pcase ph + ;; TODO: Define/derive bespoke faces. + ("Pending" 'warning) + ("Running" 'success) + ("Succeeded" 'shadow) + ("Failed" 'error)))) + (propertize ph 'face face) + ph))) + (ready ".status.containerStatuses[?(.ready==true)].name" 6 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + (lambda (cs) + (if (string= cs "") "0" + (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs))))) + :right-align t) + (total ".status.containerStatuses[*].name" 6 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + (lambda (cs) + (if (string= cs "") "0" + (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs))))) + :right-align t) + (starttime ".status.startTime" 20)) + :logs t + :prefix (("A" "Attach" kubed-attach) + ("X" "Execute" kubed-exec) + ("F" "Forward Port" kubed-forward-port-to-pod)) + :suffixes ([ ("L" "Logs" kubed-transient-logs-for-pod) + ("X" "Exec" kubed-pods-exec) + ("a" "Attach" kubed-pods-attach)] + [ :pad-keys t + ("C-d" "Dired" kubed-pods-dired) + ("s" "Shell" kubed-pods-shell) + ("F" "Forward port" kubed-pods-forward-port)]) + (dired "C-d" "Start Dired in" + (kubed-tramp-assert-support) + (dired (kubed-remote-file-name + kubed-list-context kubed-list-namespace pod))) + (shell "s" "Start shell in" + (kubed-tramp-assert-support) + (let* ((default-directory (kubed-remote-file-name + kubed-list-context kubed-list-namespace pod))) + (shell + (concat "*Kubed Shell " + (kubed-display-resource-short-description + "pods" pod kubed-list-context kubed-list-namespace) + "*")))) + (attach "a" "Attach to remote process running on" + (kubed-attach pod (kubed-read-container pod "Container" t + kubed-list-context + kubed-list-namespace) + kubed-list-context kubed-list-namespace t t)) + (exec "X" "Execute command in" + (let ((container (kubed-read-container pod "Container" t + kubed-list-context + kubed-list-namespace)) + (cmd-args (split-string-and-unquote + (read-string "Execute command: ")))) + (kubed-exec pod (car cmd-args) container kubed-list-context + kubed-list-namespace t t (cdr cmd-args)))) + (forward-port "F" "Forward local network port to remote port of" + (let ((local-port (read-number "Forward local port: "))) + (kubed-forward-port-to-pod + pod local-port + (read-number (format "Forward local port %d to remote port: " + local-port)) + kubed-list-context + kubed-list-namespace)))) + +;;;###autoload (autoload 'kubed-display-namespace "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-namespace "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-namespaces "kubed" nil t) +;;;###autoload (autoload 'kubed-list-namespaces "kubed" nil t) +;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t) +;;;###autoload (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource namespace + ((phase ".status.phase" 10 + nil ; sorting function + (lambda (ph) + (if-let ((face (pcase ph + ;; TODO: Define/derive bespoke faces. + ("Active" 'success) + ("Terminating" 'shadow)))) + (propertize ph 'face face) + ph))) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :namespaced nil + :prefix (("S" "Set" kubed-set-namespace)) + :create + ((name &optional context) + "Create Kubernetes namespace NAME in CONTEXT. + +Interactively, prompt for NAME and use the current context by default. +With a prefix argument, prompt for CONTEXT instead." + (interactive + (let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (list (read-string "Create namespace with name: ") context))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "create" "namespace" name + (when context (list "--context" context)))) + (user-error "Failed to create Kubernetes namespace with name `%s'" name)) + (kubed-update "namespaces" (or context (kubed-local-context))) + (message "Created Kubernetes namespace with name `%s'." name)) + (set "s" "Set current namespace to" + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (when (eq (char-after) ?*) + (tabulated-list-put-tag " ")) + (forward-line))) + (kubed-set-namespace namespace kubed-list-context) + (tabulated-list-put-tag + (propertize "*" 'help-echo "Current namespace")))) + +;;;###autoload (autoload 'kubed-display-persistentvolume "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-persistentvolume "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-persistentvolumes "kubed" nil t) +;;;###autoload (autoload 'kubed-list-persistentvolumes "kubed" nil t) +;;;###autoload (autoload 'kubed-create-persistentvolume "kubed" nil t) +;;;###autoload (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource persistentvolume () :namespaced nil) + +;;;###autoload (autoload 'kubed-display-service "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-service "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-services "kubed" nil t) +;;;###autoload (autoload 'kubed-list-services "kubed" nil t) +;;;###autoload (autoload 'kubed-create-service "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-service "kubed" nil t) +;;;###autoload (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource service + ((type ".spec.type" 12) + (clusterip ".spec.clusterIP" 16) + (externalip ".spec.externalIPs[*]" 16) + (ports ".spec.ports[*].port" 6) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :logs t) + +;;;###autoload (autoload 'kubed-display-secret "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-secret "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-secrets "kubed" nil t) +;;;###autoload (autoload 'kubed-list-secrets "kubed" nil t) +;;;###autoload (autoload 'kubed-create-secret "kubed" nil t) +;;;###autoload (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource secret + ((type ".type" 32) (creationtimestamp ".metadata.creationTimestamp" 20))) + +(defun kubed-create-job-from-cronjob (name cronjob &optional context namespace) + "Create Kubernetes job with name NAME from cronjob CRONJOB. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace to use for the job, +defaulting to the current namespace." + (interactive + (let ((name (read-string "Create job with name: ")) + (context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create-job)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list name + (kubed-read-cronjob + (format "Create job `%s' from cronjob" name) nil nil context namespace) + context namespace))) + (let* ((context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context)))) + (unless (zerop + (process-file + (kubed-kubectl-program) nil nil nil + "create" "job" name "--from" (concat "cronjob/" cronjob) + "-n" namespace "--context" context)) + (user-error "Failed to create Kubernetes job `%s'" name)) + (kubed-update "jobs" context namespace) + (message "Created Kubernetes job `%s'." name))) + +;;;###autoload (autoload 'kubed-display-job "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-job "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-jobs "kubed" nil t) +;;;###autoload (autoload 'kubed-list-jobs "kubed" nil t) +;;;###autoload (autoload 'kubed-create-job "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-job "kubed" nil t) +;;;###autoload (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource job + ((status ".status.conditions[0].type" 10) (starttime ".status.startTime" 20)) + :prefix (("c" "Create from Cron" kubed-create-job-from-cronjob)) + :logs t + :create + ((name image &optional context namespace command) + "Create Kubernetes job with name NAME executing COMMAND in IMAGE. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace to use for the job, +defaulting to the current namespace." + (interactive + (let ((name (read-string "Create job with name: ")) + (image nil) (context nil) (namespace nil) (command nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create-job)) + (cond + ((string-match "--image=\\(.+\\)" arg) + (setq image (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "-- =\\(.+\\)" arg) + (setq command (split-string-and-unquote (match-string 1 arg)))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (unless image + (setq image (kubed-read-container-image "Image to run in job"))) + (list name image context namespace command))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "create" "job" name "--image" image + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context)) + (when command (cons "--" command))))) + (user-error "Failed to create Kubernetes job `%s'" name)) + (message "Created Kubernetes job `%s'." name))) + +;;;###autoload +(defun kubed-watch-deployment-status (dep &optional context namespace cb) + "Show and update status of Kubernetes deployment DEP in a dedicate buffer. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. CB is an optional callback function to call with +no arguments when the deployment ends. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." + (interactive + (let (context namespace) + (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (kubed-read-deployment "Watch deployment status" nil nil + context namespace) + context namespace))) + (let* ((buf (get-buffer-create "*kubed-deployment-status*")) + (context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context)))) + (with-current-buffer buf (erase-buffer)) + (make-process + :name "*kubed-watch-deployment-status*" + :buffer buf + :file-handler t + :command (list (kubed-kubectl-program) "rollout" "status" + "deployment" dep "-n" namespace "--context" context) + :sentinel (when cb + (lambda (_proc status) + (when (member status '("finished\n" + "exited abnormally with code 1\n")) + (funcall cb))))) + (display-buffer buf))) + +(defcustom kubed-restart-deployment-watch-status t + "Whether to pop up a progress buffer when restarting Kubernetes deployments." + :type 'boolean) + +;;;###autoload +(defun kubed-scale-deployment (dep reps &optional context namespace) + "Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." + (interactive + (let (reps context namespace) + (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--replicas=\\(.+\\)" arg) + (setq reps (string-to-number (match-string 1 arg)))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (kubed-read-deployment "Scale deployment" nil nil context namespace) + (or reps (read-number "Number of replicas: ")) context namespace))) + (let* ((context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context)))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "scale" "deployment" dep + "--replicas" (number-to-string reps) + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context))))) + (user-error "Failed to scale Kubernetes deployment `%s'" dep)) + (message "Scaled Kubernetes deployment `%s' to %d replicas." dep reps))) + +;;;###autoload +(defun kubed-restart-deployment (dep &optional context namespace) + "Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; NAMESPACE is the namespace of DEP, defaulting to +the current namespace. CB is an optional callback function to call with +no arguments when the deployment ends. + +Interactively, prompt for DEP. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT." + (interactive + (let (context namespace) + (dolist (arg (kubed-transient-args 'kubed-transient-rollout)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (kubed-read-deployment "Restart deployment" nil nil + context namespace) + context namespace))) + (let* ((context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context))) + (host (file-remote-p default-directory))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "rollout" "restart" "deployment" dep + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context))))) + (user-error "Failed to restart Kubernetes deployment `%s'" dep)) + (message "Restarting Kubernetes deployment `%s'." dep) + (when kubed-restart-deployment-watch-status + (kubed-watch-deployment-status + dep context namespace + (lambda () + (kubed-update "deployments" context namespace host)))))) + +;;;###autoload (autoload 'kubed-display-deployment "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-deployment "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-deployments "kubed" nil t) +;;;###autoload (autoload 'kubed-list-deployments "kubed" nil t) +;;;###autoload (autoload 'kubed-create-deployment "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-deployment "kubed" nil t) +;;;###autoload (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource deployment + (( ready ".status.readyReplicas" 6 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + (lambda (s) (if (string= s "") "0" s)) + :right-align t) + ( updated ".status.updatedReplicas" 8 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + (lambda (s) (if (string= s "") "0" s)) + :right-align t) + ( available ".status.availableReplicas" 10 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + (lambda (s) (if (string= s "") "0" s)) + :right-align t) + ( reps ".status.replicas" 4 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + ( creationtimestamp ".metadata.creationTimestamp" 20)) + :prefix (("R" "Restart" kubed-restart-deployment) + ("W" "Watch" kubed-watch-deployment-status) + ("$" "Scale" kubed-scale-deployment)) + :logs t + :suffixes ([("L" "Logs" kubed-transient-logs-for-deployment) + ("W" "Watch" kubed-deployments-watch) + ("R" "Restart" kubed-deployments-restart) + ("$" "Scale" kubed-deployments-scale)]) + :create + ((name images &optional context namespace replicas port command) + "Deploy IMAGES to Kubernetes in deployment with name NAME. + +Optional argument NAMESPACE is the namespace to use for the deployment, +defaulting to the current namespace, REPLICAS in the number of replicas +to create for each image, PORT is the port to expose, and COMMAND is an +optional command to run in the images." + (interactive + (let ((name (read-string "Create deployment with name: ")) + (images nil) (replicas nil) (port nil) (command nil) + (context nil) (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create-deployment)) + (cond + ((string-match "--replicas=\\(.+\\)" arg) + (setq replicas (string-to-number (match-string 1 arg)))) + ((string-match "--image=\\(.+\\)" arg) + (push (match-string 1 arg) images)) + ((string-match "--port=\\(.+\\)" arg) + (setq port (string-to-number (match-string 1 arg)))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "-- =\\(.+\\)" arg) + (setq command (split-string-and-unquote (match-string 1 arg)))))) + (unless images + (setq images (kubed-read-container-image "Images to deploy" nil t))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list name images context namespace replicas port command))) + (let* ((context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context)))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "create" "deployment" name + (append + (mapcar (lambda (image) (concat "--image=" image)) images) + (when namespace (list (concat "--namespace=" namespace))) + (when context (list (concat "--context=" context))) + (when replicas (list (format "--replicas=%d" replicas))) + (when port (list (format "--port=%d" port))) + (when command (cons "--" command))))) + (user-error "Failed to create Kubernetes deployment `%s'" name)) + (message "Created Kubernetes deployment `%s'." name) + (kubed-update "deployments" context namespace))) + (restart "R" "Restart" + (kubed-restart-deployment deployment kubed-list-context kubed-list-namespace) + (unless kubed-restart-deployment-watch-status + (message "Deployment restarting") + (kubed-list-update t))) + (watch "W" "Watch" (kubed-watch-deployment-status + deployment kubed-list-context kubed-list-namespace)) + (scale "$" "Scale" (kubed-scale-deployment + deployment (if current-prefix-arg + (prefix-numeric-value current-prefix-arg) + (read-number "Number of replicas: ")) + kubed-list-context kubed-list-namespace))) + +;;;###autoload (autoload 'kubed-display-replicaset "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-replicaset "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-replicasets "kubed" nil t) +;;;###autoload (autoload 'kubed-list-replicasets "kubed" nil t) +;;;###autoload (autoload 'kubed-create-replicaset "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-replicaset "kubed" nil t) +;;;###autoload (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource replicaset + ((reps ".status.replicas" 4 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (ownerkind ".metadata.ownerReferences[0].kind" 12) + (ownername ".metadata.ownerReferences[0].name" 16) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :logs t) + +;;;###autoload (autoload 'kubed-display-daemonset "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-daemonset "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-daemonsets "kubed" nil t) +;;;###autoload (autoload 'kubed-list-daemonsets "kubed" nil t) +;;;###autoload (autoload 'kubed-create-daemonset "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-daemonset "kubed" nil t) +;;;###autoload (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource daemonset + ((desired ".status.desiredNumberScheduled" 8 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (current ".status.currentNumberScheduled" 8 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (ready ".status.numberReady" 6 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (updated ".status.updatedNumberScheduled" 8 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (available ".status.numberAvailable" 10 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :logs t) + +;;;###autoload (autoload 'kubed-display-statefulset "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-statefulset "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-statefulsets "kubed" nil t) +;;;###autoload (autoload 'kubed-list-statefulsets "kubed" nil t) +;;;###autoload (autoload 'kubed-create-statefulset "kubed" nil t) +;;;###autoload (autoload 'kubed-logs-for-statefulset "kubed" nil t) +;;;###autoload (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource statefulset + ((reps ".status.replicas" 4 + (lambda (l r) (< (string-to-number l) (string-to-number r))) + nil ; formatting function + :right-align t) + (ownerkind ".metadata.ownerReferences[0].kind" 12) + (ownername ".metadata.ownerReferences[0].name" 16) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :logs t) + +(defun kubed-cronjob-suspended-p (cj &optional context ns) + "Return non-nil if cronjob CJ in CONTEXT and namespace NS is suspended." + (equal (car (with-temp-buffer + (apply #'process-file + (kubed-kubectl-program) nil t nil + "get" "cronjobs" cj + "-o" "custom-columns=SUSPENDED:.spec.suspend" "--no-headers" + (append + (when ns (list "-n" ns)) + (when context (list "--context" context)))) + (string-lines (buffer-string) t))) + "true")) + +;;;###autoload (autoload 'kubed-display-cronjob "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-cronjob "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-cronjobs "kubed" nil t) +;;;###autoload (autoload 'kubed-list-cronjobs "kubed" nil t) +;;;###autoload (autoload 'kubed-create-cronjob "kubed" nil t) +;;;###autoload (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource cronjob + ((schedule ".spec.schedule" 20) + (suspend ".spec.suspend" 20) + (lastschedule ".status.lastScheduleTime" 20) + (lastsuccess ".status.lastSuccessfulTime" 20) + (activejob ".status.active[0].name" 36)) + :create + ((name image schedule &optional context namespace command) + "Schedule IMAGE to run in a cronjob with name NAME according to SCHEDULE. + +Optional argument NAMESPACE is the namespace to use for the cronjob, +defaulting to the current namespace. COMMAND is a list of strings that +represent a program followed by its arguments, if it non-nil then it +overrides the default command IMAGE runs." + (interactive + (let ((name (read-string "Create cronjob with name: ")) + (image nil) + (schedule nil) + (command nil) + (context nil) + (namespace nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create-cronjob)) + (cond + ((string-match "--image=\\(.+\\)" arg) + (setq image (match-string 1 arg))) + ((string-match "--schedule=\\(.+\\)" arg) + (setq schedule (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "-- =\\(.+\\)" arg) + (setq command (split-string-and-unquote (match-string 1 arg)))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (unless image + (setq image (kubed-read-container-image "Image to run"))) + (unless schedule + (setq schedule (read-string "Cron schedule: " "* * * * *"))) + (list name image schedule context namespace command))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "create" "cronjob" name + "--image" image "--schedule" schedule + (append + (when context (list "--context" context)) + (when namespace (list "--namespace" namespace)) + (when command (cons "--" command))))) + (user-error "Failed to create Kubernetes cronjob `%s'" name)) + (message "Created Kubernetes cronjob `%s'." name)) + ;; Commands in *kubed-cronjobs* buffer. + ( toggle-suspension "T" "Toggle suspension of" + (kubed-patch "cronjobs" cronjob + (format + "{\"spec\": {\"suspend\": %s}}" + (if (kubed-cronjob-suspended-p + cronjob kubed-list-context kubed-list-namespace) + "false" "true")) + kubed-list-context kubed-list-namespace)) + ( create-job "j" "Create job from" + (kubed-create-job-from-cronjob + (read-string "Create job with name: ") cronjob + kubed-list-context kubed-list-namespace))) + +;;;###autoload (autoload 'kubed-display-ingressclass "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-ingressclass "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-ingressclasses "kubed" nil t) +;;;###autoload (autoload 'kubed-list-ingressclasss "kubed" nil t) +;;;###autoload (autoload 'kubed-create-ingressclass "kubed" nil t) +;;;###autoload (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource ingressclass + ((controller ".spec.controller" 32) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :namespaced nil + :plural ingressclasses) + +;;;###autoload (autoload 'kubed-display-ingress "kubed" nil t) +;;;###autoload (autoload 'kubed-edit-ingress "kubed" nil t) +;;;###autoload (autoload 'kubed-delete-ingresses "kubed" nil t) +;;;###autoload (autoload 'kubed-list-ingresss "kubed" nil t) +;;;###autoload (autoload 'kubed-create-ingress "kubed" nil t) +;;;###autoload (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap) +(kubed-define-resource ingress + ((class ".spec.ingressClassName" 8) + (creationtimestamp ".metadata.creationTimestamp" 20)) + :plural ingresses + :create + ((name rules &optional context namespace class default-backend annotations) + "Create Kubernetes ingress with name NAME and rules RULES. + +Optional argument NAMESPACE is the namespace to use for the ingress, +defaulting to the current namespace. CLASS is the ingress class, +ANNOTATIONS are a list of annotations for the created ingress, and +DEFAULT-BACKEND is the service to use as a backend for unhandled URLs." + (interactive + (let ((name (read-string "Create ingress with name: ")) + (rules nil) + (context nil) + (namespace nil) + (class nil) + (annotations nil) + (default-backend nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create-ingress)) + (cond + ((string-match "--rule=\\(.+\\)" arg) + (push (match-string 1 arg) rules)) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--class=\\(.+\\)" arg) + (setq class (match-string 1 arg))) + ((string-match "--default-backend=\\(.+\\)" arg) + (setq default-backend (match-string 1 arg))) + ((string-match "--annotation=\\(.+\\)" arg) + (push (match-string 1 arg) annotations)))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (unless rules (setq rules (kubed-read-ingress-rules))) + (list name rules context namespace class default-backend annotations))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "create" "ingress" name + (append + (mapcan (lambda (rule) (list "--rule" rule)) rules) + (when namespace (list "--namespace" namespace)) + (when context (list "--context" context)) + (when class (list "--class" class)) + (when default-backend + (list "--default-backend" default-backend)) + (mapcan (lambda (ann) (list "--annotation" ann)) + annotations)))) + (user-error "Failed to create Kubernetes ingress `%s'" name)) + (message "Created Kubernetes ingress `%s'." name))) + +;; TODO: Events may be numerous. Need to only get a few. +;; ;;;###autoload (autoload 'kubed-list-events "kubed" nil t) +;; ;;;###autoload (autoload 'kubed-event-prefix-map "kubed" nil t 'keymap) +;; (kubed-define-resource event +;; ((last ".lastTimestamp" 20) +;; (type ".type" 10) +;; (reason ".reason" 20) +;; (objectkind ".involvedObject.kind" 12) +;; (objectname ".involvedObject.name" 16) +;; (message ".message" 36))) + +(defun kubed-contexts () + "Return list of Kubernetes contexts." + (with-temp-buffer + (process-file (kubed-kubectl-program) nil t nil + "config" "get-contexts" "-o" "name") + (string-lines (buffer-string) t))) + +(defun kubed-current-context () + "Return current Kubernetes context." + (car (with-temp-buffer + (unless (zerop (process-file (kubed-kubectl-program) nil t nil + "config" "current-context")) + (error "Failed to get current `kubectl' context")) + (string-lines (buffer-string) t)))) + +(defun kubed-read-default-namespace-non-empty (context) + "Prompt for a default namespace for CONTEXT, refusing empty input." + (let ((ns (kubed-read-namespace + (format "Default namespace for context `%s'" context) + nil nil context))) + (when (string-empty-p ns) + (user-error "You didn't specify a default namespace")) + ns)) + +(defun kubed-default-context-and-namespace () + "Return default context and namespace as a cons cell (CONTEXT . NAMESPACE)." + (let ((host (file-remote-p default-directory))) + (or (alist-get host kubed-default-context-and-namespace-alist nil nil #'equal) + (setf (alist-get host kubed-default-context-and-namespace-alist nil nil #'equal) + (let ((context (kubed-current-context))) + (cons context + (or (kubed-current-namespace context) + (kubed-read-default-namespace-non-empty context)))))))) + +(defun kubed-default-context () + "Return default `kubectl' context." + (car (kubed-default-context-and-namespace))) + +(defun kubed-default-namespace () + "Return default Kubernetes namespace in the default context." + (cdr (kubed-default-context-and-namespace))) + +(defun kubed-remote-file-name-p (file-name) + "Check whether FILE-NAME is a Kubed Tramp remote file name." + ;; We use this function to heuristically check file names without + ;; loading `kubed-tramp' (which in turn loads `tramp'). + (string-match-p "[/|]kubedv[0-9]+:" file-name)) + +(defun kubed-local-context () + "Return Kubernetes context local to the current buffer." + (or kubed-list-context + (nth 2 kubed-display-resource-info) + (and (kubed-remote-file-name-p default-directory) + (kubed-tramp-context default-directory)) + (kubed-default-context))) + +(defvar kubed-context-history nil + "History list for `kubed-read-context'.") + +(defun kubed-read-context (prompt &optional default) + "Prompt with PROMPT for a Kubernetes context. + +Optional argument DEFAULT is the minibuffer default argument." + (completing-read (format-prompt prompt default) + (kubed-contexts) + nil 'confirm nil 'kubed-context-history default)) + +;;;###autoload +(defun kubed-use-context (context) + "Set default `kubectl' context to CONTEXT. + +This command sets the global `kubectl' default context, and updates the +value of `kubed-default-context-and-namespace-alist' accordingly. + +Interactively, prompt for CONTEXT with completion." + (interactive + (list (kubed-read-context "Use context" (kubed-local-context)))) + (unless (zerop + (process-file + (kubed-kubectl-program) nil nil nil + "config" "use-context" context)) + (user-error "Failed to use Kubernetes context `%s'" context)) + (let ((namespace (or (kubed-current-namespace context) + (kubed-read-namespace + (format "Default namespace to use in context `%s'" context) + nil nil context)))) + (setf (alist-get (file-remote-p default-directory) + kubed-default-context-and-namespace-alist nil nil #'equal) + (cons context namespace)) + (message "Default context is now `%s', namespace `%s'." context namespace))) + +;;;###autoload +(defun kubed-rename-context (old new) + "Rename Kubernetes context OLD to NEW." + (interactive + (let ((old (kubed-read-context "Rename context" (kubed-local-context)))) + (list old (read-string (format-prompt "Rename context to" old) + nil 'kubed-context-history old)))) + (unless (zerop + (process-file + (kubed-kubectl-program) nil nil nil + "config" "rename-context" old new)) + (user-error "Failed to rename Kubernetes context `%s' to `%s'" old new)) + (message "Renamed Kubernetes context `%s' to `%s'." old new)) + +;;;###autoload +(defun kubed-display-config () + "Display current Kubernetes client settings in a YAML buffer." + (interactive) + (let* ((buf (get-buffer-create "*kubed-config*")) + (fun (lambda (&optional _ _) + (let ((inhibit-read-only t) + (target (current-buffer))) + (buffer-disable-undo) + (with-temp-buffer + (unless (zerop + (process-file + (kubed-kubectl-program) nil t nil "config" "view")) + (error "`kubectl config view' failed")) + (let ((source (current-buffer))) + (with-current-buffer target + (replace-buffer-contents source) + (set-buffer-modified-p nil) + (buffer-enable-undo)))))))) + (with-current-buffer buf + (funcall fun) + (goto-char (point-min)) + (run-hooks 'kubed-yaml-setup-hook) + (setq-local revert-buffer-function fun)) + (display-buffer buf))) + +(defun kubed-current-namespace (&optional context) + "Return current Kubernetes namespace for context CONTEXT. + +If no namespace is configured for CONTEXT, return nil." + (car + (with-temp-buffer + (process-file (kubed-kubectl-program) nil t nil + "config" "view" "-o" + (format "jsonpath={.contexts[?(.name==\"%s\")].context.namespace}" + (or context (kubed-current-context)))) + (string-lines (buffer-string) t)))) + +(defun kubed-local-namespace () + "Return Kubernetes namespace in CONTEXT local to the current buffer." + (or kubed-list-namespace + (nth 3 kubed-display-resource-info) + (and (kubed-remote-file-name-p default-directory) + (kubed-tramp-namespace default-directory)) + (kubed-default-namespace))) + +(defun kubed-local-context-and-namespace () + "Return (CONTEXT . NAMESPACE) pair local to the current buffer." + (or (when-let ((context kubed-list-context)) + (cons context + (or kubed-list-namespace + (kubed-current-namespace context)))) + (when-let ((context (nth 2 kubed-display-resource-info))) + (cons context + (or (nth 3 kubed-display-resource-info) + (kubed-current-namespace context)))) + (when-let ((context (and (kubed-remote-file-name-p default-directory) + (kubed-tramp-context default-directory)))) + (cons context (kubed-tramp-namespace default-directory))) + (kubed-default-context-and-namespace))) + +;;;###autoload +(defun kubed-set-namespace (namespace &optional context) + "Set default Kubernetes namespace in CONTEXT to NAMESPACE. + +If CONTEXT is the current default context, also update the value of user +option `kubed-default-context-and-namespace-alist' to use NAMESPACE as +the default namespace. + +Interactively, prompt for NAMESPACE and use the current context. With a +prefix argument, prompt for CONTEXT as well." + (interactive + (let* ((context (kubed-local-context)) + (context (if current-prefix-arg + (kubed-read-context "Context" context) + context))) + (list (kubed-read-namespace "Set namespace" (kubed--namespace context) + nil context) + context))) + (let ((context (or context (kubed-local-context)))) + (unless (zerop + (process-file + (kubed-kubectl-program) nil nil nil + "config" "set-context" context + "--namespace" namespace)) + (user-error "Failed to set Kubernetes namespace to `%s' in context `%s'" + namespace context)) + (let ((host (file-remote-p default-directory))) + (when (equal context + (car (alist-get host kubed-default-context-and-namespace-alist nil nil #'equal))) + (setf (alist-get host kubed-default-context-and-namespace-alist nil nil #'equal) + (cons context namespace)))) + (message "Default Kubernetes namespace for context `%s' is now `%s'." + context namespace))) + +(defcustom kubed-read-resource-definition-filter-files-by-kind t + "Whether to filter file completion candidates by their Kubernetes \"kind\". + +If this is non-nil, `kubed-read-resource-definition-file-name' only +suggests files with the right \"kind\" as completion candidates when you +call it with non-nil KIND argument. This is useful because you get more +relevant completions, but it may become slow in directories with many +large JSON and YAML files, in which case you can set this option to nil." + :type 'boolean) + +(defun kubed-read-resource-definition-file-name (&optional kind) + "Prompt for Kubernetes resource definition file name. + +Optional argument KIND is the kind of resource the file should define. +If `kubed-read-resource-definition-filter-files-by-kind' is non-nil, +this function suggests only files that define resources of kind KIND as +completion candidates." + (read-file-name + (format "%s definition file: " (or kind "Resource")) nil nil t nil + (if (and kind kubed-read-resource-definition-filter-files-by-kind + (executable-find "grep" t)) + (let ((cache (make-hash-table :test 'equal))) + (lambda (f) + (or (file-directory-p f) + (when-let ((ext (and (string-match "\\.[^.]*\\'" f) + (substring f (1+ (match-beginning 0)))))) + (or (and (member ext '("yaml" "yml")) + (pcase (gethash (expand-file-name f) cache 'noval) + ('noval + (puthash (expand-file-name f) + (zerop (process-file + "grep" nil nil nil "-i" + (format "^kind: %s$" kind) + (file-local-name (expand-file-name f)))) + cache)) + (val val))) + (and (equal ext "json") + (pcase (gethash (expand-file-name f) cache 'noval) + ('noval + (puthash (expand-file-name f) + (zerop (process-file + "grep" nil nil nil "-i" + (format "^kind: %s$" kind) + (file-local-name (expand-file-name f)))) + cache)) + (val val)))))))) + (lambda (f) + (or (file-directory-p f) + (when (string-match "\\.[^.]*\\'" f) + (member (substring f (1+ (match-beginning 0))) + '("yaml" "yml" "json")))))))) + +;;;###autoload +(defun kubed-apply (config &optional kind context) + "Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT." + (interactive + (let ((config nil) (context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-apply)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--filename=\\(.+\\)" arg) + (setq config (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (unless config + (setq config (kubed-read-resource-definition-file-name))) + (list config nil context))) + (let ((kind (or kind "resource")) + (context (or context (kubed-local-context)))) + (message "Applying Kubernetes %s configuration `%s'..." kind config) + (process-file (kubed-kubectl-program) nil nil nil + "apply" "-f" (expand-file-name config) "--context" context) + (message "Applying Kubernetes %s configuration `%s'... Done." kind config))) + +;;;###autoload +(defun kubed-create (definition &optional kind context) + "Create resource of kind KIND with definition DEFINITION via CONTEXT." + (interactive + (let ((definition nil) (context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-create)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--filename=\\(.+\\)" arg) + (setq definition (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if current-prefix-arg + (kubed-read-context "Context" cxt) + cxt)))) + (unless definition + (setq definition (kubed-read-resource-definition-file-name))) + (list definition nil context))) + (let ((kind (or kind "resource"))) + (message "Creating Kubernetes %s with definition `%s'..." kind definition) + (message "Creating Kubernetes %s with definition `%s'... Done. New %s name is `%s'." + kind definition kind + (car (with-temp-buffer + (apply #'process-file + (kubed-kubectl-program) nil t nil + "create" "-f" (expand-file-name definition) + "-o" "jsonpath={.metadata.name}" + (when context (list "--context" context))) + (string-lines (buffer-string) t)))))) + +;;;###autoload +(defun kubed-run + ( pod image + &optional context namespace port attach stdin tty rm envs command args) + "Run container IMAGE in a new Kubernetes POD. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context. NAMESPACE is the namespace in which to create POD, +defaulting to the current namespace. PORT is the port to expose, +defaulting to none. If ATTACH is non-nil, then attach to the created +image with a `comint-mode' buffer, and pop to that buffer. Non-nil +STDIN says to keep the standard input of the container open; non-nil TTY +says to allocate a TTY for the container; and non-nil RM says to remove +the container after it exits. ENVS is a list of strings \"VAR=VAL\" +which specify environment variables VAR and values VAL to give them in +the created container. ARGS are command line arguments for the +container command. If COMMAND is non-nil, ARGS consist of a complete +command line, that overrides the container command instead of just +providing it with arguments. + +Interactively, prompt for POD and IMAGE. With a prefix argument, prompt +for NAMESPACE; with a double prefix argument, also prompt for CONTEXT." + (interactive + (let ((pod nil) (image nil) (port nil) (context nil) (namespace nil) + (attach nil) (stdin nil) (tty nil) (rm nil) (envs nil) + (command nil) (args nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-run)) + (cond + ((string-match "--image=\\(.+\\)" arg) + (setq image (match-string 1 arg))) + ((string-match "--port=\\(.+\\)" arg) + (setq port (string-to-number (match-string 1 arg)))) + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((equal "--attach" arg) (setq attach t)) + ((equal "--stdin" arg) (setq stdin t)) + ((equal "--tty" arg) (setq tty t)) + ((equal "--rm" arg) (setq rm t)) + ((equal "--command" arg) (setq command t)) + ((string-match "--env=\\(.+\\)" arg) + (push (match-string 1 arg) envs)) + ((string-match "-- =\\(.+\\)" arg) + (setq args (split-string-and-unquote (match-string 1 arg)))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (setq pod (read-string "Run image in pod with name: ")) + (unless image + (setq image (read-string "Image to run: " nil 'kubed-container-image-history))) + (list pod image context namespace port attach stdin tty rm envs command args))) + (if attach + (pop-to-buffer + (apply #'make-comint "kubed-run" (kubed-kubectl-program) nil + "run" pod (concat "--image=" image) "--attach" + (append + (mapcar (lambda (env) (concat "--env=" env)) + (cons "TERM=dumb" envs)) + (when namespace (list (concat "--namespace=" namespace))) + (when stdin '("-i")) + (when tty '("-t")) + (when rm '("--rm")) + (when port (list (format "--port=%d" port))) + (when command '("--command")) + (when args (cons "--" args))))) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "run" pod (concat "--image=" image) + (append + (mapcar (lambda (env) (concat "--env=" env)) envs) + (when namespace (list (concat "--namespace=" namespace))) + (when context (list (concat "--context=" context))) + (when stdin '("-i")) + (cond + (attach '("--attach")) + (stdin '("--attach=false"))) + (when tty '("-t")) + (when rm '("--rm")) + (when port (list (format "--port=%d" port))) + (when command '("--command")) + (when args (cons "--" args))))) + (user-error "Failed to run image `%s'" image)) + (message "Image `%s' is now running in pod `%s'." image pod))) + +(defun kubed-pod-containers (pod &optional context namespace) + "Return list of containers in Kubernetes pod POD in NAMESPACE in CONTEXT." + (split-string + (car (with-temp-buffer + (apply #'process-file + (kubed-kubectl-program) nil t nil + "get" "pod" pod "-o" "jsonpath={.spec.containers[*].name}" + (append + (when namespace (list "--namespace" namespace)) + (when context (list "--context" context)))) + (string-lines (buffer-string) t))) + " ")) + +(defun kubed-pod-default-container (pod &optional context namespace) + "Return default container of Kubernetes pod POD in NAMESPACE in CONTEXT." + (car (with-temp-buffer + (apply #'process-file + (kubed-kubectl-program) nil t nil + "get" "pod" pod "-o" + "jsonpath={.metadata.annotations.kubectl\\.kubernetes\\.io/default-container}" + (append + (when namespace (list "--namespace" namespace)) + (when context (list "--context" context)))) + (string-lines (buffer-string) t)))) + +(defun kubed-read-container + (pod prompt &optional guess context namespace) + "Prompt with PROMPT for a container in POD and return its name. + +Non-nil optional argument GUESS says to try and guess which container to +use without prompting: if the pod has a +\"kubectl.kubernetes.id/default-container\" annotation, use the +container that this annotation specifes; if there's just one container, +use it; otherwise, fall back to prompting." + (let ((default (kubed-pod-default-container pod context namespace)) + (all 'unset)) + (or + ;; There's a default container, so that's our guess. + (and guess default) + ;; No default, but we're allowed to guess, so check if there's just + ;; one container, and if so that's our guess. + (and guess (setq all (kubed-pod-containers pod context namespace)) + (null (cdr all)) + (car all)) + ;; No guessing, prompt. + (completing-read (format-prompt prompt default) + (completion-table-dynamic + (lambda (_) + (if (eq all 'unset) + (setq all (kubed-pod-containers pod context namespace)) + all))) + nil t nil nil default)))) + +;;;###autoload +(defun kubed-logs + ( type resource &optional context namespace + container follow limit prefix since tail timestamps) + "Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE. + +Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is +the namespace for RESOURCE; CONTAINER is the name of the container in +RESOURCE to show logs for, or t which specifies all relevant containers. + +With a prefix argument, prompt for NAMESPACE; with a double prefix +argument, also prompt for CONTEXT." + (interactive + (let ( type resource context namespace + container follow limit prefix since tail timestamps) + (dolist (arg (kubed-transient-args 'kubed-transient-logs)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--limit-bytes=\\(.+\\)" arg) + (setq limit (string-to-number (match-string 1 arg)))) + ((string-match "--tail=\\(.+\\)" arg) + (setq tail (string-to-number (match-string 1 arg)))) + ((string-match "--since-time=\\(.+\\)" arg) + (setq since (match-string 1 arg))) + ((equal "--all-containers" arg) (setq container t)) + ((equal "--follow" arg) (setq follow t)) + ((equal "--prefix" arg) (setq prefix t)) + ((equal "--timestamps" arg) (setq timestamps t)))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (setq type (kubed-read-resource-type "Type of resource to display" + nil context)) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (setq resource (kubed-read-resource-name type "Show logs for" nil nil + context namespace)) + (list type resource context namespace + (or container + (and (string= type "pods") + (kubed-read-container resource "Container" t + context namespace))) + (or follow + (unless (bound-and-true-p transient-current-command) + kubed-logs-follow)) + limit prefix since + (or tail + (unless (or (bound-and-true-p transient-current-command) + (zerop kubed-logs-tail-lines)) + kubed-logs-tail-lines)) + timestamps))) + (let* ((context (or context (kubed-local-context))) + (namespace (or namespace (kubed--namespace context))) + (buf (generate-new-buffer + (format "*kubed-logs %s/%s%s in %s[%s]*" + type resource + (cond + ((stringp container) (concat "[" container "]")) + (container "[all containers]") + (t "")) + namespace context)))) + (with-current-buffer buf (run-hooks 'kubed-logs-setup-hook)) + (apply #'start-file-process "*kubed-logs*" buf + (kubed-kubectl-program) "logs" (concat type "/" resource) + "--context" context "-n" namespace + (append + (cond + ((stringp container) (list "-c" container)) + (container '("--all-containers"))) + (when follow '("--follow")) + (when prefix '("--prefix")) + (when timestamps '("--timestamps")) + (when since (list "--since-time" since)) + (when tail (list "--tail" (number-to-string tail))) + (when limit (list "--limit-bytes" (number-to-string limit))))) + (display-buffer buf))) + +(defvar kubed-port-forward-process-alist nil + "Alist of current port-forwarding descriptors and corresponding processes.") + +(defun kubed-port-forward-process-alist (&optional _ignored) + "Update and return value of variable `kubed-port-forward-process-alist'." + (setq kubed-port-forward-process-alist + (seq-filter (lambda (pair) + (process-live-p (cdr pair))) + kubed-port-forward-process-alist))) + +;;;###autoload +(defun kubed-forward-port-to-pod + (pod local-port remote-port context namespace) + "Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD." + (interactive + (let* ((c (kubed-local-context)) + (c (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" c) + c)) + (n (kubed--namespace c current-prefix-arg)) + (n (if current-prefix-arg + (kubed-read-namespace "Namespace" n nil c) + n)) + (p (kubed-read-pod "Forward port to pod" nil nil c n)) + (l (read-number "Local port: ")) + (r (read-number "Remote port: "))) + (list p l r c n))) + (message "Forwarding local port %d to remote port %d of pod `%s' in namespace `%s'..." + local-port remote-port pod namespace) + (push + (cons + (format "%s %d:%d in %s[%s]" pod local-port remote-port namespace context) + (apply #'start-file-process + "*kubed-port-forward*" nil + (kubed-kubectl-program) "port-forward" + pod (format "%d:%d" local-port remote-port) + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context))))) + kubed-port-forward-process-alist)) + +(defun kubed-stop-port-forward (descriptor) + "Stop Kubernetes port-forwarding with descriptor DESCRIPTOR. + +DESCRIPTOR is a string that says which port-forwarding process to stop, +it has the format \"POD LOCAL-PORT:REMOTE-PORT in NAMESPACE[CONTEXT]\", +where POD is the name of the pod that is the target of the +port-forwarding, LOCAL-PORT is the local port that is being forwarded, +REMOTE-PORT is the correspoding remote port of POD, NAMESPACE is the +namespace of POD and CONTEXT is the `kubectl' context. + +Interactively, prompt for DESCRIPTOR with completion. If there is only +one port-forwarding process, stop that process without prompting." + (interactive + (list + (cond + ((cdr (kubed-port-forward-process-alist)) + (completing-read "Stop port-forwarding: " + (completion-table-dynamic + #'kubed-port-forward-process-alist) + nil t)) + ((caar kubed-port-forward-process-alist)) + (t (user-error "No port-forwarding to Kubernetes in progress"))))) + (if-let ((pair (assoc descriptor kubed-port-forward-process-alist))) + (delete-process (cdr pair)) + (error "No port-forwarding for %s" descriptor)) + (message "Stopped port-forwarding for %s" descriptor)) + +(defvar kubed-container-image-history nil + "Minibuffer history for `kubed-read-container-image'.") + +(defun kubed-read-container-image (prompt &optional default multi) + "Prompt with PROMPT for names of container images. + +Optional argument DEFAULT is the minibuffer default argument. Non-nil +optional argument MULTI says to read multiple image names and return +them as list." + (funcall (if multi #'completing-read-multiple #'completing-read) + (format-prompt prompt default) nil nil nil nil + 'kubed-container-images-history default)) + +(defvar kubed-ingress-rule-history nil + "Minibuffer history for `kubed-read-ingress-rules'.") + +(defun kubed-read-ingress-rules () + "Prompt with PROMPT for Kubernetes ingress rules." + (let ((rules (list (read-string "Ingress rule: " + nil 'kubed-ingress-rule-history)))) + (while (not + (string-empty-p + (car (push (read-string (format-prompt "Additional rules" "done") + nil 'kubed-ingress-rule-history) + rules))))) + (nreverse (cdr rules)))) + +(defvar transient-current-command) + +(defun kubed-transient-args (&optional prefix) + "Return current arguments from transient PREFIX. + +If PREFIX is nil, it defaults to the value of `transient-current-command'." + (when-let ((prefix (or prefix (bound-and-true-p transient-current-command)))) + (and (featurep 'kubed-transient) + (fboundp 'transient-args) + (transient-args prefix)))) + +;;;###autoload +(defun kubed-attach (pod &optional container context namespace stdin tty) + "Attach to running process in CONTAINER in Kubernetes POD. + +Optional argument NAMESPACE is the namespace in which to look for POD. +Non-nil STDIN says to connect local standard input to remote process. +Non-nil TTY says to use a TTY for standard input. + +Interactively, prompt for POD; if there are multiple pod containers, +prompt for CONTAINER as well. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. +STDIN and TTY are t interactively." + (interactive + (let ((context nil) (namespace nil) (stdin t) (tty t)) + (dolist (arg (kubed-transient-args 'kubed-transient-attach)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((equal "--stdin" arg) (setq stdin t)) + ((equal "--tty" arg) (setq tty t)))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace)) + (c (kubed-read-container p "Container" t context namespace))) + (list p c context namespace stdin tty)))) + (pop-to-buffer + (apply #'make-comint "kubed-attach" (kubed-kubectl-program) nil + "attach" pod + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context)) + (when container (list "-c" container)) + (when stdin '("-i")) + (when tty '("-t")))))) + +;;;###autoload +(defun kubed-diff (definition &optional include-managed context) + "Display difference between Kubernetes resource DEFINITION and current state. + +DEFINITION is either a file name or a buffer. Interactively, prompt for +a YAML or JSON file name to use as DEFINITION. + +Optional argument CONTEXT is the `kubectl' context to use, defaulting to +the current context; non-nil INCLUDE-MANAGED (interactively, the prefix +argument) says to include managed fields in the comparison." + (interactive + (let ((definition nil) (context nil) (include-managed nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-diff)) + (cond + ((string-match "--filename=\\(.+\\)" arg) + (setq definition (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((equal "--show-managed-fields" arg) (setq include-managed t)))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (list (or definition (kubed-read-resource-definition-file-name)) + (or include-managed current-prefix-arg) + context))) + (let ((buf (get-buffer-create "*kubed-diff*")) + (args (cons "diff" + (append + (when context (list "--context" context)) + (when include-managed + (list "--show-managed-fields" "true")) + (list "-f" (if (bufferp definition) "-" + (expand-file-name definition))))))) + (with-current-buffer buf + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (fundamental-mode) + (if (bufferp definition) + (let ((tmpfile (make-temp-file "kubed"))) + (unwind-protect + (with-current-buffer definition + (write-region (point-min) (point-max) tmpfile) + (apply #'process-file (kubed-kubectl-program) + tmpfile buf nil args)) + (delete-file tmpfile))) + (apply #'process-file (kubed-kubectl-program) + nil t nil args)) + (setq buffer-read-only t) + (diff-mode) + (goto-char (point-min))) + (display-buffer buf))) + +;;;###autoload +(defun kubed-exec + (pod command &optional container context namespace stdin tty args) + "Execute COMMAND with ARGS in CONTAINER in Kubernetes POD. + +Optional argument NAMESPACE is the namespace in which to look for POD. +Non-nil STDIN says to connect local standard input to remote process. +Non-nil TTY says to use a TTY for standard input. + +Interactively, prompt for POD; if there are multiple pod containers, +prompt for CONTAINER as well. With a prefix argument, prompt for +NAMESPACE too. With a double prefix argument, also prompt for CONTEXT. +STDIN and TTY are t interactively." + (interactive + (let ((context nil) (namespace nil) (stdin t) (tty t) (command nil) (args nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-exec)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((equal "--stdin" arg) (setq stdin t)) + ((equal "--tty" arg) (setq tty t)) + ((string-match "-- =\\(.+\\)" arg) + (setq args (split-string-and-unquote (match-string 1 arg)) + command (car args) + args (cdr args))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (unless command + (setq args (split-string-and-unquote + (read-string "Execute command: ")) + command (car args) + args (cdr args))) + (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace)) + (c (kubed-read-container p "Container" t context namespace))) + (list p command c context namespace stdin tty args)))) + (pop-to-buffer + (apply #'make-comint "kubed-exec" (kubed-kubectl-program) nil + "exec" pod + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context)) + (when container (list "-c" container)) + (when stdin '("-i")) + (when tty '("-t")) + (list "--" command) + args)))) + +(defvar kubed-patch-history nil + "Minibuffer history for `kubed-read-patch'.") + +(defun kubed-read-patch () + "Prompt for a Kubernetes resource patch in JSON or YAML format." + (read-string "Patch (JSON or YAML): " nil 'kubed-patch-history)) + +;;;###autoload +(defun kubed-patch (type name patch &optional context namespace strategy) + "Patch Kubernetes resource NAME of TYPE with patch PATCH. + +Optional argument NAMESPACE is the namespace in which to look for NAME. +STRATEGY is the patch type to use, one of \"json\", \"merge\" and +\"strategic\", defaulting to \"strategic\". + +Interactively, prompt for TYPE, NAME and PATCH. With a prefix argument, +prompt for NAMESPACE too. With a double prefix argument, also prompt +for CONTEXT." + (interactive + (let ((type nil) (context nil) (namespace nil) (strategy nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-patch)) + (cond + ((string-match "--namespace=\\(.+\\)" arg) + (setq namespace (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))) + ((string-match "--type=\\(.+\\)" arg) + (setq strategy (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (unless namespace + (setq namespace (kubed--namespace context current-prefix-arg))) + (list (kubed-read-resource-type "Resource type to patch" nil context) + (kubed-read-resource-name type "Resource to patch" nil nil context namespace) + (kubed-read-patch) context namespace strategy))) + (message "Applying patch to `%s'..." name) + (unless (zerop + (apply #'process-file + (kubed-kubectl-program) nil nil nil + "patch" type name "-p" patch + (append + (when namespace (list "-n" namespace)) + (when context (list "--context" context)) + (when strategy (list "--type" strategy))))) + (user-error "Patching `%s' failed" name)) + (message "Applying patch to `%s'... Done." name)) + +(defvar kubed--proxy-alist nil + "Alist associating `kubectl' context names and their proxy processes.") + +;;;###autoload +(defun kubed-proxy + (&optional addr port api-prefix www-dir www-prefix context) + "Start a web server on localhost proxying the Kubernetes API server. + +ADDR and PORT are the local address and port to bind the proxy server +to. They default to 127.0.0.1 and 8001, respectively. API-PREFIX is a +prefix under which to proxy the Kubernetes API. WWW-DIR is a local +directory to serve under WWW-PREFIX, which defaults to \"/static/\". +Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the +local context." + (interactive + (let ((addr nil) (port nil) + (api-prefix nil) (www-dir nil) (www-prefix nil) + (context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-proxy)) + (cond + ((string-match "--address=\\(.+\\)" arg) + (setq addr (match-string 1 arg))) + ((string-match "--port=\\(.+\\)" arg) + (setq port (string-to-number (match-string 1 arg)))) + ((string-match "--api-prefix=\\(.+\\)" arg) + (setq api-prefix (match-string 1 arg))) + ((string-match "--www-dir=\\(.+\\)" arg) + (setq www-dir (match-string 1 arg))) + ((string-match "--www-prefix=\\(.+\\)" arg) + (setq www-prefix (match-string 1 arg))) + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (list addr port api-prefix www-dir www-prefix context))) + (let ((context (or context (kubed-local-context)))) + (when-let ((proc (alist-get context kubed--proxy-alist + nil nil #'string=)) + ((process-live-p proc))) + (if (y-or-n-p (concat "Proxy already running for context `" context + "'. Stop it and start new proxy?")) + (kill-process proc) + (user-error "Proxy already running for context `%s'" context)) + (message "Stopped proxy for context `%s'." context)) + (setf (alist-get context kubed--proxy-alist nil nil #'string=) + (apply #'start-file-process (format "*kubed-proxy[%s]*" context) nil + (kubed-kubectl-program) "proxy" + "--context" context + (append + (when addr (list "--address" addr)) + (when port (list "--port" (number-to-string port))) + (when api-prefix (list "--api-prefix" api-prefix)) + (when www-dir (list "--www-dir" www-dir)) + (when www-prefix (list "--www-prefix" www-prefix))))) + (message "Started proxy for context `%s'." context))) + +;;;###autoload +(defun kubed-stop-proxy (&optional context) + "Stop local proxy for context CONTEXT, defaulting to the local context." + (interactive + (let ((context nil)) + (dolist (arg (kubed-transient-args 'kubed-transient-proxy)) + (cond + ((string-match "--context=\\(.+\\)" arg) + (setq context (match-string 1 arg))))) + (unless context + (setq context + (let ((cxt (kubed-local-context))) + (if (equal current-prefix-arg '(16)) + (kubed-read-context "Context" cxt) + cxt)))) + (list context))) + (let ((context (or context (kubed-local-context)))) + (if-let ((proc (alist-get context kubed--proxy-alist + nil nil #'string=)) + ((process-live-p proc))) + (kill-process proc) + (user-error "No proxy running for context `%s'" context)) + (message "Stopped proxy for context `%s'." context))) + +(with-eval-after-load 'help-mode + ;; Wait for `help-mode' to define `help-xref'. It's always loaded by + ;; the time we actually need it in `kubed-explain'. + (define-button-type 'kubed-explain + :supertype 'help-xref + 'help-function 'kubed-explain + 'help-echo "mouse-2, RET: explain")) + +(defvar kubed-resource-field-history nil + "Minibuffer history for `kubed-read-resource-field'.") + +(defun kubed-api-resources (&optional context only-namespaced) + "Return list of resource types in the context CONTEXT. + +Non-nil optional argument ONLY-NAMESPACED says to return only namespaced +resource types." + (mapcar + (lambda (line) + (car (split-string line))) + (with-temp-buffer + (apply #'process-file + (kubed-kubectl-program) nil t nil + "api-resources" "--no-headers" + (append + (when only-namespaced '("--namespaced=true")) + (when context (list (concat "--context=" context))))) + (string-lines (buffer-string) t)))) + +(defun kubed-resource-names (type context &optional namespace) + "Return list of Kubernetes resources of type TYPE in NAMESPACE via CONTEXT." + (unless (kubed--alist (file-remote-p default-directory) type context namespace) + (let ((proc (kubed-update type context namespace))) + (while (process-live-p proc) + (accept-process-output proc 1)))) + (mapcar #'car + (alist-get 'resources + (kubed--alist + (file-remote-p default-directory) + type context namespace)))) + +(defun kubed-read-resource-name (type prompt &optional default multi context namespace) + "Prompt with PROMPT for Kubernetes resource name of type TYPE. + +Optional argument DEFAULT is the minibuffer default argument; non-nil +MULTI says to read multiple names and return them as a list; CONTEXT is +the `kubectl' context to use, defaulting to the local context; and +NAMESPACE is the namespace to use, or nil if TYPE is non-namespaced." + (funcall + (if multi #'completing-read-multiple #'completing-read) + (format-prompt prompt default) + (let ((table 'unset)) + (lambda (s p a) + (if (eq a 'metadata) + `(metadata (category . ,(intern (concat "kubernetes-" type)))) + (when (eq table 'unset) + (setq table (kubed-resource-names + type (or context (kubed-local-context)) namespace))) + (complete-with-action a table s p)))) + nil 'confirm nil (intern (concat "kubed-" type "-history")) default)) + +(defun kubed-read-resource-type (prompt &optional default context) + "Prompt with PROMPT for Kubernetes resource type in context CONTEXT. + +Optional argument DEFAULT is the minibuffer default argument." + (completing-read + (format-prompt prompt default) + (kubed-api-resources context) + nil 'confirm nil nil default)) + +(defun kubed-read-resource-field (prompt &optional default context) + "Prompt with PROMPT for Kubernetes resource type or field name. + +Optional argument DEFAULT is the minibuffer default argument, and +CONTEXT is the `kubectl' context to use." + (completing-read + (format-prompt prompt default) + (lambda (s p a) + (unless (eq a 'metadata) + (let ((start 0)) + (while (string-match "\\." s start) + (setq start (match-end 0))) + (if (eq (car-safe a) 'boundaries) + `(boundaries ,start . ,(and (string-match "\\." (cdr a)) + (match-beginning 0))) + (let ((table + (if (zerop start) + ;; Complete resource type. + (kubed-api-resources context) + ;; Complete (sub-)field name. + (with-temp-buffer + (process-file + (kubed-kubectl-program) nil t nil + "explain" (substring s 0 start)) + (goto-char (point-min)) + (let ((res nil)) + (while (re-search-forward + (rx line-start (+ " ") (group-n 1 (* alnum)) "\t") + nil t) + (push (match-string 1) res)) + res))))) + (if a (complete-with-action a table (substring s start) p) + ;; `try-completion'. + (let ((comp (complete-with-action a table (substring s start) p))) + (if (stringp comp) (concat (substring s 0 start) comp) comp)))))))) + nil 'confirm nil 'kubed-resource-field-history default)) + +;;;###autoload +(defun kubed-explain (field) + "Show help buffer with explanation about Kubernetes resource FIELD." + (interactive + (list (kubed-read-resource-field "Explain type or field"))) + (let ((help-buffer-under-preparation t)) + (help-setup-xref (list #'kubed-explain field) + (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer (help-buffer) + (insert (substitute-quotes + (concat "`kubed explain " field "' says:\n\n"))) + (save-excursion + ;; Add button that goes to parent. + (goto-char (point-min)) + (when (re-search-forward (rx " " + (group-n 1 (* graph)) + "." + (+ (not (any ?.))) + line-end) + nil t) + (help-xref-button 1 'kubed-explain (match-string 1)))) + + (process-file (kubed-kubectl-program) nil t nil "explain" field) + ;; Buttonize references to other fields. + (goto-char (point-min)) + (while (re-search-forward (rx line-start + (+ " ") + (group-n 1 (* alnum)) + "\t") + nil t) + (help-xref-button 1 'kubed-explain + (concat field "." (match-string 1)))))))) + +(defvar kubed-kubectl-command-history nil + "Minibuffer history for `kubed-kubectl-command'.") + +(declare-function cobra-read-command-line "cobra" + (prompt initial &optional hist)) + +(defun kubed-read-kubectl-command (prompt &optional initial) + "Prompt with PROMPT for a `kubectl' command line. + +Optional argument is INITIAL added to the initial minibuffer input +following the value of `kubed-kubectl-program' and a space character." + (let* ((kubectl (kubed-kubectl-program)) + (init (if (consp initial) + (cons (concat kubectl " " (car initial)) + (+ (length kubectl) 1 (cdr initial))) + (concat kubectl " " initial)))) + (cobra-read-command-line prompt init 'kubed-kubectl-command-history))) + +;;;###autoload +(defun kubed-kubectl-command (command) + "Execute `kubectl' COMMAND. + +This function calls `shell-command' (which see) to do the work. + +Interactively, prompt for COMMAND with completion for `kubectl' arguments." + (interactive + (list (kubed-read-kubectl-command + "Command: " + (let* ((args (kubed-transient-args)) + (prefix (and (fboundp 'transient-prefix-object) + (transient-prefix-object))) + (scope (and prefix (fboundp 'eieio-oref) + (eieio-oref prefix 'scope)))) + (or + (seq-find (apply-partially #'string-prefix-p "--context=") args) + ;; No context argument, add one. + (push (concat "--context=" (kubed-local-context)) args)) + (concat (string-join (append scope args) " ") " "))))) + (shell-command command)) + +;;;###autoload (autoload 'kubed-prefix-map "kubed" nil t 'keymap) +(defvar-keymap kubed-prefix-map + :doc "Prefix keymap for Kubed commands." + :prefix 'kubed-prefix-map + "p" 'kubed-pod-prefix-map + "N" 'kubed-namespace-prefix-map + "s" 'kubed-service-prefix-map + "S" 'kubed-secret-prefix-map + "j" 'kubed-job-prefix-map + "d" 'kubed-deployment-prefix-map + "i" 'kubed-ingress-prefix-map + "c" 'kubed-cronjob-prefix-map + "k" #'kubed-transient + "L" #'kubed-logs + "C" #'kubed-use-context + "+" #'kubed-create + "*" #'kubed-apply + "R" #'kubed-run + "=" #'kubed-diff + "E" #'kubed-explain + "P" #'kubed-patch + ":" #'kubed-proxy + "RET" #'kubed-display-resource + "!" #'kubed-kubectl-command) + +(defvar-keymap kubed-menu-map + :doc "Keymap with Kubed menu entries." + :prefix 'kubed-menu-map + "" '("Namespaces..." . kubed-namespace-menu-map) + "" '("Pods..." . kubed-pod-menu-map) + "" '("Persistent Volumes..." . kubed-persistentvolume-menu-map) + "" '("Services..." . kubed-service-menu-map) + "" '("Secrets..." . kubed-secret-menu-map) + "" '("Jobs..." . kubed-job-menu-map) + "" '("Deployments..." . kubed-deployment-menu-map) + "" '("Replica Sets..." . kubed-replicaset-menu-map) + "" '("Daemon Sets..." . kubed-daemonset-menu-map) + "" '("Stateful Sets..." . kubed-statefulset-menu-map) + "" '("Cron Jobs..." . kubed-cronjob-menu-map) + "" '("Ingress Classes..." . kubed-ingressclass-menu-map) + "" '("Ingresses..." . kubed-ingress-menu-map) + "" '("Proxy Kubernetes API" . kubed-proxy) + "" '("Patch Resource" . kubed-patch) + "" '("Diff Config with Live" . kubed-diff) + "" '("Invoke kubectl" . kubed-kubectl-command) + "" '("Explain Type or Field" . kubed-explain) + "" '("Set Current Context" . kubed-use-context) + "" '("View Logs" . kubed-logs) + "" '("Run Image" . kubed-run) + "" '("Apply Config" . kubed-apply) + "" '("Create Resource" . kubed-create) + "" '("Display Resource" . kubed-display-resource)) + +;;;###autoload +(define-minor-mode kubed-menu-bar-mode + "Add \"Kubernetes\" menu to your menu bar." + :global t + (if kubed-menu-bar-mode + (keymap-set-after (current-global-map) + " " '("Kubernetes" . kubed-menu-map)) + (keymap-global-unset " "))) + +(defvar reporter-prompt-for-summary-p) + +(defun kubed-submit-bug-report () + "Report a Kubed issue to the maintainers via email." + (interactive) + (require 'reporter) + (let ((reporter-prompt-for-summary-p t)) + (reporter-submit-bug-report + "Kubed Development <~eshel/kubed-devel@lists.sr.ht>" + (format "Kubed") + '(kubed-kubectl-program) + nil nil + (propertize " " + 'display + (propertize + "Insert your bug report below. +If possible, specify where you got Emacs, kubectl and Kubed, +and include a recipe for reproducing your issue. +[This line and the above text are not included in your report.]" + 'face 'italic))))) + +(provide 'kubed) +;;; kubed.el ends here diff --git a/elpa/kubed-0.6.1/kubed.info b/elpa/kubed-0.6.1/kubed.info new file mode 100644 index 00000000..a1900696 Binary files /dev/null and b/elpa/kubed-0.6.1/kubed.info differ diff --git a/elpa/kubed-0.6.1/kubed.texi b/elpa/kubed-0.6.1/kubed.texi new file mode 100644 index 00000000..6db39ad8 --- /dev/null +++ b/elpa/kubed-0.6.1/kubed.texi @@ -0,0 +1,970 @@ +\input texinfo @c -*- texinfo -*- +@c %**start of header +@setfilename kubed.info +@settitle Kubed: Kubernetes, Emacs, done! +@documentencoding UTF-8 +@documentlanguage en +@set MAINTAINERSITE @uref{https://eshelyaron.com,maintainer webpage} +@set MAINTAINER Eshel Yaron +@set MAINTAINEREMAIL @email{me@eshelyaron.com} +@set MAINTAINERCONTACT @uref{mailto:me@eshelyaron.com,contact the maintainer} +@c %**end of header + +@copying +This manual is for Kubed 0.6.1, a rich Emacs interface for Kubernetes. + +Copyright @copyright{} 2024-2026 Eshel Yaron. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. +@end quotation +@end copying + +@dircategory Emacs +@direntry +* Kubed: (kubed). Kubernetes, Emacs, done! +@end direntry + +@finalout +@titlepage +@title Kubed: Kubernetes, Emacs, done! +@author Eshel Yaron (@email{me@@eshelyaron.com}) +@end titlepage + +@contents + +@ifnottex +@node Top +@top Kubed: Kubernetes, Emacs, done! + +This manual is for Kubed 0.6.1, a rich Emacs interface for Kubernetes. + +@end ifnottex + +@menu +* Overview:: Introduction to Kubed +* Getting Started:: First steps with Kubed +* Usage:: Using Kubed to interact with Kubernetes +* Extending Kubed:: Adding support for your custom resources +* Contributing:: Get involved in Kubed development +* Indices:: +@end menu + +@node Overview +@chapter Overview + +@cindex Kubed +@cindex kubed +Kubed is a rich Kubernetes interface within Emacs. It helps you work +with your Kubernetes clusters and deployments with the full power of +@command{kubectl}, and with the comfort and confidence of an intuitive +interactive interface. + +@float +@ifset split +@image{../../assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png} +@end ifset +@ifclear split +@image{assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png} +@end ifclear +@caption{Pods, logs, shells, YAMLs, all in one integrated interface} +@end float + +You can use Kubed to: + +@itemize +@item +Browse and manage Kubernetes workloads +@item +Connect to pods and edit files or execute commands +@item +Create new resources, edit and delete them +@item +Work with multiple clusters +@item +Interact with clusters through remote Tramp connections +@item +Get help about various Kubernetes objects +@item +@dots{} +@end itemize + +These features and others are documented in the rest of this manual, +along with many options that Kubed provides for you to customize its +behavior. + +@node Getting Started +@chapter Getting Started + +@cindex installation + +Get Kubed from GNU ELPA with @kbd{M-x package-install}, or use your +favorite Emacs package manager to install Kubed from Git. You can +clone the Kubed Git repository from any of the following locations: + +@itemize +@item +@url{https://git.sr.ht/~eshel/kubed} +@item +@url{https://github.com/eshelyaron/kubed.git} +@item +@url{git://git.eshelyaron.com/kubed.git} +@end itemize + +@cindex requirements +To get started with Kubed, all you need is @command{kubectl} and Emacs. + +Kubed tries to find @command{kubectl} in the directories listed in the +Emacs variable @code{exec-path}. When Emacs is started from a shell, it +initializes @code{exec-path} from the shell's @env{PATH} environment +variable which normally includes the location of @command{kubectl} in +common @command{kubectl} installations. If Emacs doesn't find the +@command{kubectl} executable via @code{exec-path}, you can tell Kubed +where to find it by customizing @code{kubed-kubectl-program}. + +@defopt kubed-kubectl-program +Name of @command{kubectl} executable file to use. You can also set this +option as a connection-local variable (@pxref{Connection Variables,,, +emacs}) to use a different @command{kubectl} executable on specific +remote hosts. @xref{Kubed over Tramp}. +@end defopt + +@node Usage +@chapter Usage + +Kubed comes with a large number of Emacs command for interacting with +Kubernetes. Some commands perform one action on one resource, while +others show you a menu with many resources and let you interact with any +number of them. Some commands are specific to one type of resources, +while others act on resources of any type. There are different ways to +use Kubed, depending on your use case. + +The two most important entry points for Kubed are +@code{kubed-prefix-map} and @code{kubed-transient}: + +@anchor{Definition of kubed-prefix-map} +@cindex global prefix keymap +@cindex prefix keymap, global commands +@cindex keymap, for global commands +@defvr Keymap kubed-prefix-map +Keymap with bindings for many useful Kubed commands. +@end defvr + +The prefix keymap @code{kubed-prefix-map} gives you quick access to the +main Kubed commands. You may want to bind it to a convenient key in +your global keymap, for example: + +@lisp +(keymap-global-set "C-c k" 'kubed-prefix-map) +@end lisp + +With this binding in place, you can create a new Kubernetes resource +with @kbd{C-c k +} and attach to a running pod with @kbd{C-c k p a}. +The @kbd{C-c k} binding is just a suggestion of course, feel free to +pick any key sequence you like. + +@float + +@ifset split +@image{../../assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png} +@end ifset +@ifclear split +@image{assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png} +@end ifclear + +@ifset split +@image{../../assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png} +@end ifset +@ifclear split +@image{assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png} +@end ifclear + +@caption{Use @code{kubed-prefix-map} for quick access to the main Kubed commands} +@end float + +You can also access all of the commands in @code{kubed-prefix-map} via +the menu-bar @samp{Kubernetes} menu---to add this menu to your +menu-bar, enable the global minor mode @code{kubed-menu-bar-mode}: + +@anchor{Definition of kubed-menu-bar-mode} +@deffn {Minor Mode} kubed-menu-bar-mode +Add @samp{Kubernetes} menu to your menu bar. +@end deffn + +The other important entry point that Kubed provides for exploring and +performing different Kubernetes operations is @code{kubed-transient}: + +@deffn Command kubed-transient +Open the main Kubed transient menu. +@end deffn + +This command pops up the Kubed transient menu, which gives you +interactive guidance for invoking Kubed commands. +@xref{Top,,,transient}. + +The following sections describe in detail the various Kubed commands. + +@menu +* Display Resource:: +* Browse Resources:: +* Resource Logs:: +* Context and Namespace:: +* Transient Menus:: +* Scale Deployment:: +* Kubed over Tramp:: +@end menu + +@node Display Resource +@section Display Resource + +You can view the YAML description of any resource in your Kubernetes +cluster. In Kubed, this is referred to as @dfn{displaying} the given +resource. The following commands display a Kubernetes resource: + +@deffn Command kubed-display-resource +Display a Kubernetes resource. +@end deffn + +@deffn Command kubed-display-pod +@deffnx Command kubed-display-deployment +@deffnx Command kubed-display-namespace +@deffnx Command kubed-display-@var{foo} +Display Kubernetes resource of a given type. +@end deffn + +Command @code{kubed-display-resource} can display any Kubernetes +resource. It prompts you to select a resource type and a resource +name, and displays that resource in a dedicated buffer. By default, +this command assumes you want to display a resource that is in the +current namespace, but if you invoke @code{kubed-display-resource} +with a prefix argument (@kbd{C-u}) and choose a namespaced resource +type, then it also lets you select the namespace of the resource. +With a double prefix argument, it lets you select which +@command{kubectl} context to use too. @xref{Context and Namespace}. + +If you have @code{kubed-prefix-map} bound to @kbd{C-c k}, you can +invoke @code{kubed-display-resource} with @kbd{C-c k @key{RET}}. This +command is also available from the menu-bar ``Kubernetes'' menu +(@pxref{Definition of kubed-menu-bar-mode}), and from the transient +``Kubernetes Display'' menu (@pxref{Transient Menus}). + +You can also display the resource at point in resources list buffers +by simply typing @kbd{@key{RET}}. @xref{Browse Resources}. + +Kubed also provides a dedicated @code{kubed-display-@var{foo}} command +for each supported resource type @var{foo}. These commands are just +like @code{kubed-display-resource}, except that they do not prompt you +for a type, since they are type-specific. For example, +@code{kubed-display-pod} only prompts you for a pod name, and then +displays it like @code{kubed-display-resource} does. + +You can invoke these commands by adding a type-specific key before +@kbd{@key{RET}} in @kbd{C-c k @key{RET}}: @kbd{C-c k p @key{RET}} +invokes @code{kubed-display-pod}, @kbd{C-c k d @key{RET}} invokes +@code{kubed-display-deployment}, and so on. + +When Kubed prepares a buffer for displaying a resource, it runs the +hook @code{kubed-yaml-setup-hook} right after populating the buffer +with the YAML description of the resource: + +@defopt kubed-yaml-setup-hook +List of functions to call, in order, to prepare YAML buffers. The +first function on this hook is normally the major mode you want to use +for YAML buffers that display Kubernetes resources. By default, this +is the list @code{(yaml-ts-mode view-mode)}. +@end defopt + +In addition, Kubed enables a bespoke minor mode +@code{kubed-display-resource-mode} in buffers that display Kubernetes +resources: + +@deffn {Minor Mode} kubed-display-resource-mode +Minor mode for buffers that display a Kubernetes resource. +@end deffn + +@noindent +This minor mode does the following: + +@itemize +@item +It shows the word @samp{Kubed} in the mode line, so you know you're +seeing a rendered Kubernetes resource, rather than any old YAML file. +@item +It allows you to @emph{bookmark} the resource your viewing and your +position in its YAML description with the regular Emacs bookmarks +commands (@pxref{Bookmarks,,,emacs}), namely @kbd{C-x r m}. +@item +@kindex C-c C-j +@findex kubed-display-resource-jump-to-list +It binds the key sequence @kbd{C-c C-j} to command +@code{kubed-display-resource-jump-to-list}, which pops up the +resources list buffer for the type of the displayed resource, and +takes you to the line corresponding to it. +@item +@kindex C-c C-c +@findex kubed-display-resource-replace +@kindex C-c C-= +@findex kubed-display-resource-diff +@kindex C-x C-q +@findex read-only-mode +It binds @kbd{C-c C-c} to command +@code{kubed-display-resource-replace}, which lets you apply any +changes that you make in the YAML buffer back to the resource. When +you hit @kbd{C-c C-c}, Kubed asks you for confirmation before +proceeding; you can reply with @kbd{d} (@samp{diff}) to show a diff +between the current state of the resource and the current buffer +contents. You can also display this diff anytime with @kbd{C-c C-=}. +Note that by default Kubed displays resources in read-only buffers, so +you may need to hit @kbd{C-x C-q} (@code{read-only-mode}) before +making changes in the buffer. +@item +@kindex C-x x g +@findex revert-buffer +@findex revert-buffer-quick +It lets you repopulate the buffer with updated information about the +resource with @kbd{C-x x g} (@code{revert-buffer-quick}) and +@w{@kbd{M-x revert-buffer}}. This is also useful if you edit the +resource and want to restart from a clean slate. +@end itemize + +@float +@ifset split +@image{../../assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png} +@end ifset +@ifclear split +@image{assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png} +@end ifclear +@caption{Type @kbd{C-x C-q} in a resource YAML buffer to edit it, @kbd{C-c C-c} to apply} +@end float + +@node Browse Resources +@section Browse Resources + +Kubed gives you an interactive list of resources for each type, that +you access with the @code{kubed-list-@var{resource}s} commands, such +as @code{kubed-list-pods}. + +These commands are bound to @kbd{l} in Kubed's type-specific prefix +keymaps, most of which are accessible via the global +@code{kubed-prefix-map} by default (@pxref{Definition of +kubed-prefix-map}). So if you've bound @code{kubed-prefix-map} to +@kbd{C-c k}, you can pop up the pods list with @kbd{C-c k p l}, the +deployments list with @kbd{C-c k d l}, the jobs list with @w{@kbd{C-c +k j l}}, etc. Normally, Kubed shows the list of resources in the +current namespace, but if you invoke these commands with a prefix +argument (say, @kbd{C-u C-c k p l}), they first prompt you to select a +namespace, and then show resources in the namespace you selected. + +The list of @var{resource}s in shown a buffer called @w{@file{*Kubed +@var{resource}s@@@var{namespace}[@var{context}]*}}, where +@var{context} is a @command{kubectl} context, and @var{namespace} is a +namespace in @var{context}. For example, Kubed shows the list of pods +in namespace @samp{default} for context @samp{minikube} in buffer +@file{*Kubed pos@@default[minikube]}. For non-namespaced resources, +the @w{@samp{@@@var{namespace}}} part is omitted. + +Each resource type has its own major mode for list buffers with +type-specific commands and operations, but they are all also derived +from a shared parent mode. The pods list uses the +@code{kubed-pods-mode} (@samp{Kubernetes Pods}) major mode, the list +of Kubernetes deployments uses @code{kubed-deployments-mode}, and so +on. + +@float +@ifset split +@image{../../assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png} +@end ifset +@ifclear split +@image{assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png} +@end ifclear +@caption{Browse your pods, deployments, and other resources with Kubed list buffers} +@end float + +The common parent major mode is @code{kubed-list-mode}: + +@deffn {Major Mode} kubed-list-mode +Major mode for listing generic Kubernetes resources. +@end deffn + +This mode provides the following commands for all type-specific +derived modes: + +@table @kbd +@kindex @key{?} +@findex kubed-list-transient +@item @key{?} +Show help in transient menu (@code{kubed-list-transient}). +@kindex @key{RET} +@findex kubed-list-select-resource +@item @key{RET} +Display the resource at point in the current window +(@code{kubed-list-select-resource}). +@kindex o +@findex kubed-list-select-resource-other-window +@item o +Display the resource at point in another window and select that window +(@code{kubed-list-select-resource-other-window}). +@kindex C-o +@findex kubed-list-display-resource +@item C-o +Display the resource at point in another window without selecting it +(@code{kubed-list-display-resource}). +@kindex D +@findex kubed-list-delete +@item D +Delete the resource at point (@code{kubed-list-delete}). +@kindex e +@findex kubed-list-edit +@item e +Edit the resource at point (@code{kubed-list-edit}). +@kindex P +@findex kubed-list-patch +@item P +Patch the resource at point (@code{kubed-list-patch}). +@kindex g +@findex kubed-list-update +@item g +Update the resources list by fetching new information from Kubernetes +(@code{kubed-list-update}). +@kindex / +@findex kubed-list-set-filter +@item / +Filter the current list of resources (@code{kubed-list-set-filter}). +@xref{List Filter}. +@kindex d +@findex kubed-list-mark-for-deletion +@item d +Mark the resource at point for deletion +(@code{kubed-list-mark-for-deletion}). Resources marked for deletion +have a @samp{D} in the beginning of their line. +@kindex x +@findex kubed-list-delete-marked +@item x +Delete marked resources (@code{kubed-list-delete-marked}). +@kindex u +@findex kubed-list-unmark +@item u +Unmark from resource at point (@code{kubed-list-unmark}). +@kindex w +@findex kubed-list-copy-as-kill +@item w +Copy name of resource at point into the kill ring +(@code{kubed-list-copy-as-kill}). +@kindex n +@findex next-line +@item n +Move point to the next line (@code{next-line}). +@kindex p +@findex previous-line +@item p +Move point to the previous line (@code{previous-line}). +@kindex @key{TAB} +@findex kubed-list-next-column +@item @key{TAB} +Move point to the next column. If point is already at the last +column, move to the first column of the next line instead +(@code{kubed-list-next-column}). +@kindex S-@key{TAB} +@findex kubed-list-previous-column +@item S-@key{TAB} +Move point to the previous column. If point is already at the first +column, move to the last column of the previous line instead +(@code{kubed-list-previous-column}). +@kindex S +@findex tabulated-list-sort +@item S +Sort lines by the column at point (@code{tabulated-list-sort}). +@kindex | +@findex kubed-list-fit-column-width-to-content +@item | +Fit width of column at point to its content +(@code{kubed-list-fit-column-width-to-content}). With non-negative +prefix argument @var{n} (for example, @kbd{0 |}), fit @var{n}th +column. With negative prefix argument (@kbd{- |}), fit all columns. +@kindex @{ +@findex tabulated-list-narrow-current-column +@item @{ +Narrow the column at point +(@code{tabulated-list-narrow-current-column}). +@kindex @} +@findex tabulated-list-widen-current-column +@item @} +Widen the column at point +(@code{tabulated-list-widen-current-column}). +@end table + +In addition, you can bookmark any Kubed resources list buffer with the +usual @kbd{C-x r m}. @xref{Bookmarks,,,emacs}. + +Note that @code{kubed-list-mode} (and its type-specific derivatives) +bind the @kbd{g} key, which is commonly bound to @code{revert-buffer}, +to @code{kubed-list-update}. The difference between these commands is +that @code{revert-buffer} only refreshes the list display, without +fetching updated data from Kubernetes. You can still invoke +@code{revert-buffer} with @kbd{C-x x g} or @kbd{M-x}, if you need it. + +@vindex kubed-list-mode-line-format +Whenever Kubed is fetching data from Kubernetes to update a resources +list buffer, the mode line of that list buffer shows the @samp{[...]} +indicator. You can set user option @code{kubed-list-mode-line-format} +to customize this indicator. + +@menu +* List Filter:: +@end menu + +@node List Filter +@subsection Filtering Resource Lists + +In all Kubernetes resource list buffers, you can use @kbd{/} +(@code{kubed-list-set-filter}) to @dfn{filter} the list of resources. +This command sets the filter of the current buffer, which specifies +conditions on resources (lines). Resources that don't satisfy the +conditions are hidden, so you can focus on those that do. + +Filters can be simple (@dfn{atomic filters}) or complex (@dfn{composed +filters}). In the simple case, you enter a filter in the minibuffer +in the format @w{@samp{@var{op} @var{col} @var{val}}}, where @var{op} +is a comparison operator, one of @samp{=}, @samp{~}, @samp{<} and +@samp{>}; @var{col} is a column name; and @var{val} is a value to +compare to values of @var{col} with @var{op}. + +If @var{op} is @samp{=}, it says to keep only lines whose @var{col} +equals @var{val}. If @var{op} is @samp{~}, it says to keep lines +whose @var{col} matches the @var{val} as a regular expression. +@samp{<} and @samp{>} compare column values to numeric values. For +example, the filter @samp{= Name foobar} keeps only resources whose +name is @samp{foobar}. To include whitespace in @var{val}, wrap +@var{val} in double quotes: @samp{= Name "foo bar"}. + +The possible values of @var{op} and their meanings are defined in +@code{kubed-list-filter-operator-alist}, which is a user option you +can use to add or change the meaning of filter operators: + +@defopt kubed-list-filter-operator-alist +Association list of filter operators and corresponding Emacs Lisp +functions. See the documentation string of this option for specifics. +@end defopt + +You can use more refined filters by composing simple filters. To add +another filter that resources must satisfy, wrap your two filters in +parentheses and put them next to each other: + +@lisp +(= Name foobar) (~ Namespace kube) +@end lisp + +@noindent +This filter keeps only resources whose name is @samp{foobar} in +namespaces that include @samp{kube} as a substring, it expresses the +conjunction of the two simple filters. + +To negate a simple filter, put a single quote ahead of it, like so: + +@lisp +(= Name foobar) '(~ Namespace kube) +@end lisp + +@noindent +This matches resources named @samp{foobar} in namespaces that do +@emph{not} contain @samp{kube}. + +To specify a disjunction of simple filters (and negated simple +filters), add another level of nesting: + +@lisp +((= Name spam) (= Name foobar)) '(~ Namespace kube) +@end lisp + +@noindent +This filter matches resources named either @samp{spam} or +@samp{foobar}, in namespaces that do not contain @samp{kube}. + +While entering a filter in the minibuffer, @kbd{@key{TAB}} completion +is available for column names and values. To clear the filter, just +exit the minibuffer with an empty input. + +@node Resource Logs +@section Resource Logs + +Kubed lets you view logs of containers running in Kubernetes, using +@command{kubectl logs} under the hood. The most general command for +viewing logs is @code{kubed-logs}, which is bound to @kbd{L} in +@code{kubed-prefix-map} (@pxref{Definition of kubed-prefix-map}): + +@deffn Command kubed-logs +Show logs for containers running in a Kubernetes resource. This command +asks you for a resource type and name, and pops up a buffer with the +logs of the containers running in that resource. +@end deffn + +In resource list buffers that support logs---such as those for pods, +deployments, services, and jobs---you can view logs for the resource +at point directly: + +@table @kbd +@kindex l +@findex kubed-list-logs +@item l +Show logs for the resource at point (@code{kubed-list-logs}). Kubed +opens a new buffer with the log output. + +@kindex L +@item L +Open a type-specific logs transient menu for the resource at point, +with the resource pre-selected. Kubed also pre-populates the +@samp{--tail} and @samp{--follow} options from +@code{kubed-logs-tail-lines} and @code{kubed-logs-follow}, which you +can adjust before invoking the command. @xref{Transient Menus}. +@end table + +Two user options control the default behavior of these commands: + +@defopt kubed-logs-tail-lines +Number of most recent log lines to fetch and show when displaying +Kubernetes logs. The default is 128. Set this option to 0 to show all +available log lines without limit. +@end defopt + +@defopt kubed-logs-follow +Whether to follow new log entries when displaying Kubernetes logs. +The default is @code{t}. +@end defopt + +When Kubed sets up a buffer for displaying logs, it runs the +following hook: + +@defopt kubed-logs-setup-hook +List of functions to call, in order, to set up Kubernetes logs +buffers. The default value is @code{(view-mode)}. +@end defopt + +@node Context and Namespace +@section Context and Namespace + +Kubed uses @command{kubectl} to interact with Kubernetes clusters, and +you can use multiple @command{kubectl} @dfn{contexts} in Kubed to work +with different Kubernetes clusters in parallel. Within each context, +Kubed lets you work in multiple @dfn{namespaces} too. In general, +each buffer has its own @dfn{local context} and @dfn{local namespace}, +and Kubed commands use these local context and namespace by default. +This is similar to how different buffers have different values of +@code{default-directory} (@pxref{File Names,,,emacs}), and how that +affects commands that interact with the filesystem. + +For Kubed buffers that display a Kubernetes resource (@pxref{Display +Resource}) or a list of resources (@pxref{Browse Resources}), the +buffer-local context and namespace are the context and namespace of +the resources the buffer displays. For non-Kubed buffers, the user +option @code{kubed-default-context-and-namespace-alist} determines the +default local context and namespace. + +In addition to @command{kubectl} contexts, Kubed is aware of the +@dfn{host} on which it invokes @command{kubectl}. When +@code{default-directory} is a remote location (@pxref{Remote Files,,, +emacs}), Kubed runs @command{kubectl} on that remote host rather than on +the local machine. Each host has its own independent set of +@command{kubectl} contexts, so you can simultaneously work with +Kubernetes clusters reachable from different hosts. +@xref{Kubed over Tramp} for more details. + +@defopt kubed-default-context-and-namespace-alist +Association list mapping hosts to their default @command{kubectl} +context and Kubernetes namespace for Kubed commands. Each entry is a +cons cell @w{@code{(@var{host} . @var{context-and-namespace})}}, where +@var{host} is either a string identifying a connection to the host (as +returned by @code{file-remote-p}, e.g. @file{/ssh:user@@some.host:}), or +@code{nil} for the local host. @var{context-and-namespace} is either a +cons cell @w{@code{(@var{context} . @var{namespace})}}, or @code{nil}. +If it is @code{nil}, Kubed initializes the entry to a cons cell with the +current @command{kubectl} context and the default namespace of that +context on the first time Kubed consults this option for the given +@var{host}. + +For example, you can configure Kubed to use the @code{my-context} +context and @code{my-namespace} namespace on the local host by default +as follows: + +@lisp +(setopt kubed-default-context-and-namespace-alist + '((nil . ("my-context" . "my-namespace")))) + +;; Or, if you want to preserves other entries: + +(setf (alist-get nil kubed-default-context-and-namespace-alist) + '("my-context" . "my-namespace")) +@end lisp + +@end defopt + +@defvar kubed-default-context-and-namespace +This is an obsolete variable that served a similar purpose as +@code{kubed-default-context-and-namespace-alist} prior to Kubed gaining +support for remote hosts. For backward compatibility with user +configurations that set this variable, Kubed by default initializes the +local host entry in @code{kubed-default-context-and-namespace-alist} +from the value of this variable if it is set. +@end defvar + +As mentioned above, most Kubed commands use the buffer-local context and +namespace if available by default. It is also conventional for Kubed +commands to let you choose a different namespace if you invoke them with +a prefix argument (@kbd{C-u}), and to also let you choose a different +context if you invoke them with a double prefix argument (@kbd{C-u C-u}). + +The following functions return the buffer-local context and namespace +for the buffer in which you call them: + +@defun kubed-local-context +Return the local @command{kubectl} context for the current buffer. +@end defun + +@defun kubed-local-namespace +Return the local Kubernetes namespace for the current buffer. +@end defun + +@defun kubed-local-context-and-namespace +Return the local context and namespace for the current buffer as a +cons cell @w{@code{(@var{context} . @var{namespace})}}. +@end defun + +@node Transient Menus +@section Transient Menus + +Kubed provides a set of keyboard-driven @dfn{transient menus} +(@pxref{Top,,,transient}) that you can use to explore and invoke +various commands. Transient menus show you available commands along +with their key bindings, which helps you use many different commands +without the need to remember the key bindings for all them. +Additionally, the transient menus allow you to specify options and +switches for the commands you invoke, which may not be available when +invoking these commands directly. For example, while you can invoke +command @code{kubed-logs} directly to view logs from a container +running in Kubernetes (@pxref{Resource Logs}), the ``Kubernetes Logs'' +transient menu which you open with @code{kubed-transient-logs} lets you +set a maximum number of logs to retrieve, among other knobs and handles. + +@float + +@ifset split +@image{../../assets/kubed-transient,,,Image: The Kubed main transient menu,.png} +@end ifset +@ifclear split +@image{assets/kubed-transient,,,Image: The Kubed main transient menu,.png} +@end ifclear + +@ifset split +@image{../../assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png} +@end ifset +@ifclear split +@image{assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png} +@end ifclear + +@caption{Explore Kubed commands with transient menus} +@end float + +Command @code{kubed-transient} opens the Kubed ``root'' transient +menu, which is a dispatch that lets you access different transient +menus, such as the aforementioned ``Kubernetes Logs'' transient menu. +It's a good idea to bind @code{kubed-transient} to a convenient key: + +@lisp +(keymap-global-set "s-k" #'kubed-transient) +@end lisp + +By default, @code{kubed-transient} is bound to @kbd{k} in +@code{kubed-prefix-map}, so if you bind the prefix map to @kbd{C-c k} +you can open the root transient menu with @kbd{C-c k k}. +@xref{Definition of kubed-prefix-map}. + +In Kubed resource list buffers, type @kbd{?} to pop up a transient +menu with commands that are specific to the type of resources the +buffer displays. @xref{Browse Resources}. + +@node Scale Deployment +@section Scale Deployment + +You can use Kubed to @dfn{scale} Kubernetes a deployment, which means +setting the size of the deployment in terms of the number of replicas +it governs. + +@deffn Command kubed-scale-deployment +Scale a Kubernetes deployment. +@end deffn + +@code{kubed-scale-deployment} is bound to @kbd{$} in the +@code{kubed-deployment-prefix-map}, so if you have +@code{kubed-prefix-map} bound to @kbd{C-c k} then you can invoke it +with @kbd{C-c k d $}. @xref{Definition of kubed-prefix-map}. This +command prompts you for a deployment and then lets you select a new +number of replicas for that deployment. By default you are prompted +for deployment in the local context and namespace (@pxref{Context and +Namespace}); with a prefix argument, you can specify a different +namespace; with a double prefix argument (@kbd{C-u C-u}), you can +specify a different context too. + +In the deployments list buffer, you can scale the deployment at point +by simply typing @kbd{$}. @xref{Browse Resources}. + +@float +@ifset split +@image{../../assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png} +@end ifset +@ifclear split +@image{assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png} +@end ifclear +@caption{Scale deployments with @kbd{$} in the deployments list buffer} +@end float + +Lastly, you can scale deployments using the transient menu +@code{kubed-transient-scale-deployment}, which is available from the +main Kubed transient by pressing @kbd{$}. @xref{Transient Menus}. + +@node Kubed over Tramp +@section Kubed over Tramp + +@cindex remote hosts +@cindex Tramp, Kubed integration +@cindex @command{kubectl} on remote host +Kubed can run @command{kubectl} on remote hosts, letting you manage +Kubernetes clusters that are only reachable from a specific machine, +or use a @command{kubectl} installation that lives on a remote server. +This works by leveraging Emacs's Tramp remote file access facility +(@pxref{Top,,,tramp}). + +Essentially, Kubed respects the value of @code{default-directory} when +deciding where to run @command{kubectl}. When @code{default-directory} +refers to a local directory, Kubed invokes the local @command{kubectl}. +When @code{default-directory} refers to a remote directory (i.e., it is +a Tramp file name), Kubed instead invokes @command{kubectl} on the +corresponding remote host. This means that you can point Kubed at a +remote host simply by visiting a remote directory via Tramp---for +example, by opening a file on a remote server with @kbd{C-x C-f} and +Tramp file name syntax, such as @file{/ssh:user@@some.host:/home/user/}. + +Each remote host has its own independent set of @command{kubectl} +contexts and namespaces. Kubed keeps track of the default context and +namespace per host in the user option +@code{kubed-default-context-and-namespace-alist} +(@pxref{Context and Namespace}). When Kubed list buffers are showing +resources fetched from a remote host, the buffer name includes +@w{@samp{ from @var{host}}} to make it clear which host was used. + +@cindex @code{kubed-kubectl-program}, per-host +You may have @command{kubectl} installed at different paths on different +hosts, or you may want to use a wrapper script instead of the bare +@command{kubectl} executable on some hosts. Kubed consults the +@emph{connection-local} value of option @code{kubed-kubectl-program} to +determine how to invoke @command{kubectl}, so you can configure the +@command{kubectl} executable per host. For example, to tell Kubed to +use @file{/home/user/.local/bin/kubectl} on @samp{some.host}, add the +following to your Emacs initialization file: + +@lisp +(connection-local-set-profile-variables + 'my-kubed-profile-for-somehost + '((kubed-kubectl-program . "/home/user/.local/bin/kubectl"))) + +(connection-local-set-profiles + '(:application kubed :machine "some.host") + 'my-kubed-profile-for-somehost) +@end lisp + +@node Extending Kubed +@chapter Extending Kubed + +Kubed has built-in support for many common types of Kubernetes +resources. ``Support'' for a resource type in Kubed just means +providing common commands for working with resources of that type, +such as a command for showing the interactive list of these resources, +like @code{kubed-list-pods} for Kubernetes pods. In Kubed, the macro +@code{kubed-define-resource} is used to define these common commands +and add support for more resource types: + +@deffn Macro kubed-define-resource resource &optional properties &rest [ keyword argument ]@dots{} commands +Define commands for @var{resource}. +@end deffn + +Say you want to add support for your Kubernetes service accounts. +With @code{kubed-define-resource}, all you need to do is to add the +following line to your Emacs initialization file: + +@lisp +(kubed-define-resource serviceaccount) +@end lisp + +This line defines the following commands for you: + +@itemize +@item +@code{kubed-display-serviceaccount} +@item +@code{kubed-list-serviceaccounts} +@item +@code{kubed-edit-serviceaccount} +@item +@code{kubed-delete-serviceaccount} +@item +@code{kubed-create-serviceaccount} +@item +@code{kubed-explain-serviceaccounts} +@end itemize + +See the documentation string of @code{kubed-define-resource} +(@w{@kbd{C-h f}}) for details about the optional arguments of this +macro: the @var{properties} argument which lets you specify what Kubed +should show in the resource list buffer and the @code{commands} argument +which lets you associate additional commands with your resource type. + +@node Contributing +@chapter Contributing + +We highly appreciate all contributions, including bug reports, +patches, improvement suggestions, and general feedback! + +The best way to get in touch with the Kubed maintainers is via +@uref{https://lists.sr.ht/~eshel/kubed-devel, the Kubed mailing list}. + +@deffn Command kubed-submit-bug-report +Report a bug in Kubed to the maintainers via mail. +@end deffn + +You can use the command @kbd{M-x kubed-submit-bug-report} to easily +contact the Kubed maintainers from within Emacs. This command opens a +new buffer with a message template ready to be sent to the development +mailing list. + +@node Indices +@unnumbered Indices + +@menu +* Function Index:: +* Variable Index:: +* Keystroke Index:: +* Concept Index:: +@end menu + +@node Function Index +@unnumberedsec Function index + +@printindex fn + +@node Variable Index +@unnumberedsec Variable index + +@printindex vr + +@node Keystroke Index +@unnumberedsec Keystroke index + +@printindex ky + +@node Concept Index +@unnumberedsec Concept index + +@printindex cp + +@bye diff --git a/elpa/kubed-0.6.1/news b/elpa/kubed-0.6.1/news new file mode 100644 index 00000000..3c3099f0 --- /dev/null +++ b/elpa/kubed-0.6.1/news @@ -0,0 +1,146 @@ + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + KUBED NEWS – HISTORY OF USER-VISIBLE CHANGES + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + +This file contains the release notes for Kubed, a rich Emacs interface +for Kubernetes. + +For further details, see the Kubed manual: +[https://eshelyaron.com/kubed.html]. + + +[https://eshelyaron.com/kubed.html] + + +Version 0.6.1 on 2026-04-13 +═══════════════════════════ + + This is a maintenance release, it includes one important bug fix: + + +Fix “Invalid format string” error in Tramp integration +────────────────────────────────────────────────────── + + This version fixes a regression introduced in version 0.6.0, which + caused an error when starting a shell or opening Dired inside a pod. + + See bug report at + + + +Version 0.6.0 on 2026-04-11 +═══════════════════════════ + +Kubed now uses the remote `kubectl' on remote hosts +─────────────────────────────────────────────────── + + When you invoke Kubed commands in a buffer whose `default-directory' + points to a directory on a remote host (such as + `/ssh:user@example.com:/some/remote/dir/'), Kubed runs `kubectl' on + the remote host, so you can interact with clusters that are configured + in the remote kubeconfig and accessible from the remote host. + + Note that this is a rather extensive change, please tell us about + issues/regressions if you see any! + + +`kubed-kubectl-program' is now connection-local +─────────────────────────────────────────────── + + You can configure different `kubed-kubectl-program' values for + different hosts on which you run `kubectl' via Kubed commands, by + giving the variable a connection-local value for certain hosts. For + example: + + ┌──── + │ (connection-local-set-profile-variables + │ 'my-kubed-profile-for-somehost + │ '((kubed-kubectl-program . "/home/user/my-kubectl"))) + │ + │ (connection-local-set-profiles + │ '(:application kubed :machine "somehost.com") + │ 'my-kubed-profile-for-somehost) + └──── + + +New user option `kubed-default-context-and-namespace-alist' +─────────────────────────────────────────────────────────── + + This user option generalizes and supersedes the existing user option + `kubed-default-context-and-namespace', which is considered obsolete + but is still available. The new user option lets you set different + defaults depending on the host on which Kubed is running `kubectl'. + + +Command `kubed-transient' is now bound to `k' in `kubed-prefix-map' +─────────────────────────────────────────────────────────────────── + + This was already a recommended binding for this command, which opens + the “root” Kubed transient menu. + + +New user option `kubed-logs-follow' +─────────────────────────────────── + + The new user option `kubed-logs-follow' controls whether Kubed follows + new log entries by default when showing Kubernetes logs. It defaults + to `t'. + + +New user option `kubed-logs-tail-lines' +─────────────────────────────────────── + + Kubed commands that show logs for Kubernetes resources now fetch only + the most recent 128 log lines by default, to avoid flooding the logs + buffer with the full history of long-running workloads. You can + customize this limit with the new user option `kubed-logs-tail-lines'; + set it to 0 to fetch all available log lines. + + +Command `kubed-logs' is now bound to `L' in `kubed-prefix-map' +────────────────────────────────────────────────────────────── + + +Version 0.5.1 on 2026-02-13 +═══════════════════════════ + +Fix error with minibuffer completion for custom Kubernetes resources +──────────────────────────────────────────────────────────────────── + + +`kubed-use-context' now also updates `kubed-default-context-and-namespace' +────────────────────────────────────────────────────────────────────────── + + Setting the default `kubectl' context with `kubed-use-context' now + also updates the user option `kubed-default-context-and-namespace', + such that Kubed commands will also use the new context as a default. + + +Version 0.5.0 on 2025-06-11 +═══════════════════════════ + +DaemonSets support +────────────────── + + Kubed now provides commands for working with DaemonSets by default. + Remember that you can always configure support for additional resource + types with the `kubed-define-resource' macro! + + +Fix Tramp integration for context names with non-alphanumeric characters +──────────────────────────────────────────────────────────────────────── + + This version fixes an issue in the Kubed integration with Tramp, which + caused it to fail for `kubectl' contexts whose name includes “:” and + most other non-alphanumeric characters. + + See bug report at + + + +Version 0.4.3 on 2025-01-21 +═══════════════════════════ + + This is a maintenance release, it includes minor improvements and one + … …