diff options
| author | Michael Albinus | 2023-06-23 21:26:14 +0200 |
|---|---|---|
| committer | Michael Albinus | 2023-06-23 21:26:14 +0200 |
| commit | 77c2f05d773271cb59ebfd994b06a4075cacbfa8 (patch) | |
| tree | 44840ebc7831e8041c464f61fe094df95ed0a4b5 | |
| parent | 1c499c18afd6a709272fe60a540a27093e589fff (diff) | |
| download | emacs-77c2f05d773271cb59ebfd994b06a4075cacbfa8.tar.gz emacs-77c2f05d773271cb59ebfd994b06a4075cacbfa8.zip | |
Extend Tramp kubernetes method
* doc/misc/tramp.texi (Inline methods): Adapt kubernetes method.
* etc/NEWS: Describe changes in Tramp kubernetes method.
* lisp/net/tramp-container.el (tramp-kubernetes-context)
(tramp-kubernetes-namespace): New defcustoms.
(tramp-kubernetes--completion-function): Extend for CONTAINER.POD
syntax.
(tramp-kubernetes--host-name-regexp): New defconst.
(tramp-kubernetes--container, tramp-kubernetes--pod)
(tramp-kubernetes--current-context): New defuns.
(tramp-kubernetes--current-context-data): Simplify.
(tramp-kubernetes--context-namespace): New defun.
(tramp-methods) <kubernetes>: Respect container, context and
namespace. (Bug#59797)
(tramp-container-connection-local-default-kubernetes-variables):
New defconst. Set respective connection-local variables.
* lisp/net/tramp-sh.el (tramp-config-check): New variable.
(tramp-open-connection-setup-interactive-shell): Use it.
* lisp/net/tramp.el (tramp-methods): Adapt docstring.
(tramp-extra-expand-args): New defvar.
(tramp-expand-args): Use it.
| -rw-r--r-- | doc/misc/tramp.texi | 11 | ||||
| -rw-r--r-- | etc/NEWS | 8 | ||||
| -rw-r--r-- | lisp/net/tramp-container.el | 145 | ||||
| -rw-r--r-- | lisp/net/tramp-sh.el | 10 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 29 |
5 files changed, 161 insertions, 42 deletions
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index eb5c418728e..01f46865a39 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi | |||
| @@ -922,8 +922,15 @@ if desired. | |||
| 922 | @cindex @option{kubernetes} method | 922 | @cindex @option{kubernetes} method |
| 923 | 923 | ||
| 924 | Integration for containers in Kubernetes pods. The host name is a pod | 924 | Integration for containers in Kubernetes pods. The host name is a pod |
| 925 | name returned by @samp{kubectl get pods}. The first container in a | 925 | name returned by @samp{kubectl get pods}, or |
| 926 | pod is used. | 926 | @samp{@var{container}.@var{pod}} if an explicit container name shall |
| 927 | be used. Otherwise, the first container in a pod is used. | ||
| 928 | |||
| 929 | @vindex tramp-kubernetes-context | ||
| 930 | @vindex tramp-kubernetes-namespace | ||
| 931 | If another Kubernetes context or namespace shall be used, configure | ||
| 932 | the user options @code{tramp-kubernetes-context} and | ||
| 933 | @code{tramp-kubernetes-namespace}. | ||
| 927 | 934 | ||
| 928 | This method does not support user names. | 935 | This method does not support user names. |
| 929 | 936 | ||
| @@ -225,6 +225,14 @@ They allow accessing system containers provided by Toolbox or | |||
| 225 | sandboxes provided by Flatpak. | 225 | sandboxes provided by Flatpak. |
| 226 | 226 | ||
| 227 | +++ | 227 | +++ |
| 228 | *** Connection method "kubernetes" supports now optional container name. | ||
| 229 | The host name for Kubernetes connections can be of kind [CONTAINER.]POD, | ||
| 230 | in order to specify a dedicated container. If there is just the pod | ||
| 231 | name, the first container in the pod is taken. The new user options | ||
| 232 | 'tramp-kubernetes-context' and 'tramp-kubernetes-namespace' allow to | ||
| 233 | access pods with different context or namespace but the default one. | ||
| 234 | |||
| 235 | +++ | ||
| 228 | *** Rename 'tramp-use-ssh-controlmaster-options' to 'tramp-use-connection-share'. | 236 | *** Rename 'tramp-use-ssh-controlmaster-options' to 'tramp-use-connection-share'. |
| 229 | The old name still exists as obsolete variable alias. This user | 237 | The old name still exists as obsolete variable alias. This user |
| 230 | option controls now connection sharing for both ssh-based and | 238 | option controls now connection sharing for both ssh-based and |
diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el index 473cb1c54b8..6e8d28a3016 100644 --- a/lisp/net/tramp-container.el +++ b/lisp/net/tramp-container.el | |||
| @@ -37,19 +37,20 @@ | |||
| 37 | ;; C-x C-f /podman:USER@CONTAINER:/path/to/file | 37 | ;; C-x C-f /podman:USER@CONTAINER:/path/to/file |
| 38 | ;; | 38 | ;; |
| 39 | ;; Where: | 39 | ;; Where: |
| 40 | ;; USER is the user on the container to connect as (optional) | 40 | ;; USER is the user on the container to connect as (optional). |
| 41 | ;; CONTAINER is the container to connect to | 41 | ;; CONTAINER is the container to connect to. |
| 42 | ;; | 42 | ;; |
| 43 | ;; | 43 | ;; |
| 44 | ;; | 44 | ;; |
| 45 | ;; Open file in a Kubernetes container: | 45 | ;; Open file in a Kubernetes container: |
| 46 | ;; | 46 | ;; |
| 47 | ;; C-x C-f /kubernetes:POD:/path/to/file | 47 | ;; C-x C-f /kubernetes:[CONTAINER.]POD:/path/to/file |
| 48 | ;; | 48 | ;; |
| 49 | ;; Where: | 49 | ;; Where: |
| 50 | ;; POD is the pod to connect to. | 50 | ;; POD is the pod to connect to. |
| 51 | ;; By default, the first container in that pod will be | 51 | ;; CONTAINER is the container to connect to (optional). |
| 52 | ;; used. | 52 | ;; By default, the first container in that pod will |
| 53 | ;; be used. | ||
| 53 | ;; | 54 | ;; |
| 54 | ;; Completion for POD and accessing it operate in the current | 55 | ;; Completion for POD and accessing it operate in the current |
| 55 | ;; namespace, use this command to change it: | 56 | ;; namespace, use this command to change it: |
| @@ -63,7 +64,7 @@ | |||
| 63 | ;; C-x C-f /toolbox:CONTAINER:/path/to/file | 64 | ;; C-x C-f /toolbox:CONTAINER:/path/to/file |
| 64 | ;; | 65 | ;; |
| 65 | ;; Where: | 66 | ;; Where: |
| 66 | ;; CONTAINER is the container to connect to (optional) | 67 | ;; CONTAINER is the container to connect to (optional). |
| 67 | ;; | 68 | ;; |
| 68 | ;; If the container is not running, it is started. If no container is | 69 | ;; If the container is not running, it is started. If no container is |
| 69 | ;; specified, the default Toolbox container is used. | 70 | ;; specified, the default Toolbox container is used. |
| @@ -106,6 +107,20 @@ | |||
| 106 | :type '(choice (const "kubectl") | 107 | :type '(choice (const "kubectl") |
| 107 | (string))) | 108 | (string))) |
| 108 | 109 | ||
| 110 | (defcustom tramp-kubernetes-context nil | ||
| 111 | "Context of Kubernetes. | ||
| 112 | If it is nil, the default context will be used." | ||
| 113 | :group 'tramp | ||
| 114 | :version "30.1" | ||
| 115 | :type '(choice (const :tag "Use default" nil) | ||
| 116 | (string))) | ||
| 117 | |||
| 118 | (defcustom tramp-kubernetes-namespace "default" | ||
| 119 | "Namespace of Kubernetes." | ||
| 120 | :group 'tramp | ||
| 121 | :version "30.1" | ||
| 122 | :type 'string) | ||
| 123 | |||
| 109 | ;;;###tramp-autoload | 124 | ;;;###tramp-autoload |
| 110 | (defcustom tramp-toolbox-program "toolbox" | 125 | (defcustom tramp-toolbox-program "toolbox" |
| 111 | "Name of the Toolbox client program." | 126 | "Name of the Toolbox client program." |
| @@ -172,29 +187,83 @@ This function is used by `tramp-set-completion-function', please | |||
| 172 | see its function help for a description of the format." | 187 | see its function help for a description of the format." |
| 173 | (when-let ((default-directory tramp-compat-temporary-file-directory) | 188 | (when-let ((default-directory tramp-compat-temporary-file-directory) |
| 174 | (raw-list (shell-command-to-string | 189 | (raw-list (shell-command-to-string |
| 175 | (concat tramp-kubernetes-program | 190 | (concat |
| 176 | " get pods --no-headers " | 191 | tramp-kubernetes-program " " |
| 177 | "-o custom-columns=NAME:.metadata.name"))) | 192 | (tramp-kubernetes--context-namespace nil) |
| 178 | (names (split-string raw-list "\n" 'omit))) | 193 | " get pods --no-headers" |
| 179 | (mapcar (lambda (name) (list nil name)) (delq nil names)))) | 194 | ;; We separate pods by "|". Inside a pod, |
| 195 | ;; its name is separated from the containers | ||
| 196 | ;; by ":". Containers are separated by ",". | ||
| 197 | " -o jsonpath='{range .items[*]}{\"|\"}{.metadata.name}" | ||
| 198 | "{\":\"}{range .spec.containers[*]}{.name}{\",\"}" | ||
| 199 | "{end}{end}'"))) | ||
| 200 | (lines (split-string raw-list "|" 'omit))) | ||
| 201 | (let (names) | ||
| 202 | (dolist (line lines) | ||
| 203 | (setq line (split-string line ":" 'omit)) | ||
| 204 | ;; Pod name. | ||
| 205 | (push (car line) names) | ||
| 206 | ;; Container names. | ||
| 207 | (dolist (elt (split-string (cadr line) "," 'omit)) | ||
| 208 | (push (concat elt "." (car line)) names))) | ||
| 209 | (mapcar (lambda (name) (list nil name)) (delq nil names))))) | ||
| 210 | |||
| 211 | (defconst tramp-kubernetes--host-name-regexp | ||
| 212 | (rx (? (group (regexp tramp-host-regexp)) ".") | ||
| 213 | (group (regexp tramp-host-regexp))) | ||
| 214 | "The CONTAINER.POD syntax of kubernetes host names in Tramp.") | ||
| 215 | |||
| 216 | ;;;###tramp-autoload | ||
| 217 | (defun tramp-kubernetes--container (vec) | ||
| 218 | "Extract the container name from a kubernetes host name in VEC." | ||
| 219 | (or (let ((host (tramp-file-name-host vec))) | ||
| 220 | (and (string-match tramp-kubernetes--host-name-regexp host) | ||
| 221 | (match-string 1 host))) | ||
| 222 | "")) | ||
| 223 | |||
| 224 | ;;;###tramp-autoload | ||
| 225 | (defun tramp-kubernetes--pod (vec) | ||
| 226 | "Extract the pod name from a kubernetes host name in VEC." | ||
| 227 | (or (let ((host (tramp-file-name-host vec))) | ||
| 228 | (and (string-match tramp-kubernetes--host-name-regexp host) | ||
| 229 | (match-string 2 host))) | ||
| 230 | "")) | ||
| 231 | |||
| 232 | (defun tramp-kubernetes--current-context (vec) | ||
| 233 | "Return Kubernetes current context. | ||
| 234 | Obey `tramp-kubernetes-context'" | ||
| 235 | (or tramp-kubernetes-context | ||
| 236 | (with-tramp-connection-property nil "current-context" | ||
| 237 | (with-temp-buffer | ||
| 238 | (when (zerop | ||
| 239 | (tramp-call-process | ||
| 240 | vec tramp-kubernetes-program nil t nil | ||
| 241 | "config" "current-context")) | ||
| 242 | (goto-char (point-min)) | ||
| 243 | (buffer-substring (point) (line-end-position))))))) | ||
| 180 | 244 | ||
| 181 | (defun tramp-kubernetes--current-context-data (vec) | 245 | (defun tramp-kubernetes--current-context-data (vec) |
| 182 | "Return Kubernetes current context data as JSON string." | 246 | "Return Kubernetes current context data as JSON string." |
| 183 | (with-temp-buffer | 247 | (when-let ((current-context (tramp-kubernetes--current-context vec))) |
| 184 | (when (zerop | 248 | (with-temp-buffer |
| 185 | (tramp-call-process | 249 | (when (zerop |
| 186 | vec tramp-kubernetes-program nil t nil | 250 | (tramp-call-process |
| 187 | "config" "current-context")) | 251 | vec tramp-kubernetes-program nil t nil |
| 188 | (goto-char (point-min)) | 252 | "config" "view" "-o" |
| 189 | (let ((current-context (buffer-substring (point) (line-end-position)))) | 253 | (format |
| 190 | (erase-buffer) | 254 | "jsonpath='{.contexts[?(@.name == \"%s\")]}'" current-context))) |
| 191 | (when (zerop | 255 | (buffer-string))))) |
| 192 | (tramp-call-process | 256 | |
| 193 | vec tramp-kubernetes-program nil t nil | 257 | ;;;###tramp-autoload |
| 194 | "config" "view" "-o" | 258 | (defun tramp-kubernetes--context-namespace (vec) |
| 195 | (format | 259 | "The kubectl options for context and namespace." |
| 196 | "jsonpath='{.contexts[?(@.name == \"%s\")]}'" current-context))) | 260 | (mapconcat |
| 197 | (buffer-string)))))) | 261 | #'identity |
| 262 | `(,(when-let ((context (tramp-kubernetes--current-context vec))) | ||
| 263 | (format "--context=%s" context)) | ||
| 264 | ,(when tramp-kubernetes-namespace | ||
| 265 | (format "--namespace=%s" tramp-kubernetes-namespace))) | ||
| 266 | " ")) | ||
| 198 | 267 | ||
| 199 | ;;;###tramp-autoload | 268 | ;;;###tramp-autoload |
| 200 | (defun tramp-toolbox--completion-function (&rest _args) | 269 | (defun tramp-toolbox--completion-function (&rest _args) |
| @@ -275,12 +344,13 @@ see its function help for a description of the format." | |||
| 275 | (add-to-list 'tramp-methods | 344 | (add-to-list 'tramp-methods |
| 276 | `(,tramp-kubernetes-method | 345 | `(,tramp-kubernetes-method |
| 277 | (tramp-login-program ,tramp-kubernetes-program) | 346 | (tramp-login-program ,tramp-kubernetes-program) |
| 278 | (tramp-login-args (("exec") | 347 | (tramp-login-args (("%x") ; context and namespace. |
| 348 | ("exec") | ||
| 349 | ("-c" "%a") ; container. | ||
| 279 | ("%h") | 350 | ("%h") |
| 280 | ("-it") | 351 | ("-it") |
| 281 | ("--") | 352 | ("--") |
| 282 | ("%l"))) | 353 | ("%l"))) |
| 283 | (tramp-config-check tramp-kubernetes--current-context-data) | ||
| 284 | (tramp-direct-async (,tramp-default-remote-shell "-c")) | 354 | (tramp-direct-async (,tramp-default-remote-shell "-c")) |
| 285 | (tramp-remote-shell ,tramp-default-remote-shell) | 355 | (tramp-remote-shell ,tramp-default-remote-shell) |
| 286 | (tramp-remote-shell-login ("-l")) | 356 | (tramp-remote-shell-login ("-l")) |
| @@ -334,6 +404,23 @@ see its function help for a description of the format." | |||
| 334 | 404 | ||
| 335 | ;; Default connection-local variables for Tramp. | 405 | ;; Default connection-local variables for Tramp. |
| 336 | 406 | ||
| 407 | (defconst tramp-container-connection-local-default-kubernetes-variables | ||
| 408 | '((tramp-config-check . tramp-kubernetes--current-context-data) | ||
| 409 | ;; This variable will be eval'ed in `tramp-expand-args'. | ||
| 410 | (tramp-extra-expand-args | ||
| 411 | . (?a (tramp-kubernetes--container (car tramp-current-connection)) | ||
| 412 | ?h (tramp-kubernetes--pod (car tramp-current-connection)) | ||
| 413 | ?x (tramp-kubernetes--context-namespace (car tramp-current-connection))))) | ||
| 414 | "Default connection-local variables for remote kubernetes connections.") | ||
| 415 | |||
| 416 | (connection-local-set-profile-variables | ||
| 417 | 'tramp-container-connection-local-default-kubernetes-profile | ||
| 418 | tramp-container-connection-local-default-kubernetes-variables) | ||
| 419 | |||
| 420 | (connection-local-set-profiles | ||
| 421 | `(:application tramp :protocol ,tramp-kubernetes-method) | ||
| 422 | 'tramp-container-connection-local-default-kubernetes-profile) | ||
| 423 | |||
| 337 | (defconst tramp-container-connection-local-default-flatpak-variables | 424 | (defconst tramp-container-connection-local-default-flatpak-variables |
| 338 | `((tramp-remote-path . ,(cons "/app/bin" tramp-remote-path))) | 425 | `((tramp-remote-path . ,(cons "/app/bin" tramp-remote-path))) |
| 339 | "Default connection-local variables for remote flatpak connections.") | 426 | "Default connection-local variables for remote flatpak connections.") |
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index da34f31fea6..d8231bd5bd2 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el | |||
| @@ -4324,6 +4324,14 @@ seconds. If not, it produces an error message with the given ERROR-ARGS." | |||
| 4324 | (apply #'tramp-error-with-buffer | 4324 | (apply #'tramp-error-with-buffer |
| 4325 | (tramp-get-connection-buffer vec) vec 'file-error error-args))))) | 4325 | (tramp-get-connection-buffer vec) vec 'file-error error-args))))) |
| 4326 | 4326 | ||
| 4327 | (defvar tramp-config-check nil | ||
| 4328 | "A function to be called with one argument, VEC. | ||
| 4329 | It should return a string which is used to check, whether the | ||
| 4330 | configuration of the remote host has been changed (which would | ||
| 4331 | require to flush the cache data). This string is kept as | ||
| 4332 | connection property \"config-check-data\". | ||
| 4333 | This variable is intended as connection-local variable.") | ||
| 4334 | |||
| 4327 | (defun tramp-open-connection-setup-interactive-shell (proc vec) | 4335 | (defun tramp-open-connection-setup-interactive-shell (proc vec) |
| 4328 | "Set up an interactive shell. | 4336 | "Set up an interactive shell. |
| 4329 | Mainly sets the prompt and the echo correctly. PROC is the shell | 4337 | Mainly sets the prompt and the echo correctly. PROC is the shell |
| @@ -4370,7 +4378,7 @@ process to set up. VEC specifies the connection." | |||
| 4370 | vec "uname" | 4378 | vec "uname" |
| 4371 | (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\"")))) | 4379 | (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\"")))) |
| 4372 | (config-check-function | 4380 | (config-check-function |
| 4373 | (tramp-get-method-parameter vec 'tramp-config-check)) | 4381 | (buffer-local-value 'tramp-config-check (process-buffer proc))) |
| 4374 | (old-config-check | 4382 | (old-config-check |
| 4375 | (and config-check-function | 4383 | (and config-check-function |
| 4376 | (tramp-get-connection-property vec "config-check-data"))) | 4384 | (tramp-get-connection-property vec "config-check-data"))) |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index e7928e4e1f4..cbd4e1611eb 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -300,13 +300,6 @@ pair of the form (KEY VALUE). The following KEYs are defined: | |||
| 300 | and container methods do. If it is a list of strings, they | 300 | and container methods do. If it is a list of strings, they |
| 301 | are used to construct the remote command. | 301 | are used to construct the remote command. |
| 302 | 302 | ||
| 303 | * `tramp-config-check' | ||
| 304 | A function to be called with one argument, VEC. It should | ||
| 305 | return a string which is used to check, whether the | ||
| 306 | configuration of the remote host has been changed (which | ||
| 307 | would require to flush the cache data). This string is kept | ||
| 308 | as connection property \"config-check-data\". | ||
| 309 | |||
| 310 | * `tramp-copy-program' | 303 | * `tramp-copy-program' |
| 311 | This specifies the name of the program to use for remotely copying | 304 | This specifies the name of the program to use for remotely copying |
| 312 | the file; this might be the absolute filename of scp or the name of | 305 | the file; this might be the absolute filename of scp or the name of |
| @@ -4954,14 +4947,30 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") | |||
| 4954 | ;; Result. | 4947 | ;; Result. |
| 4955 | target-alist)) | 4948 | target-alist)) |
| 4956 | 4949 | ||
| 4950 | (defvar tramp-extra-expand-args nil | ||
| 4951 | "Method specific arguments.") | ||
| 4952 | |||
| 4957 | (defun tramp-expand-args (vec parameter &rest spec-list) | 4953 | (defun tramp-expand-args (vec parameter &rest spec-list) |
| 4958 | "Expand login arguments as given by PARAMETER in `tramp-methods'. | 4954 | "Expand login arguments as given by PARAMETER in `tramp-methods'. |
| 4959 | PARAMETER is a symbol like `tramp-login-args', denoting a list of | 4955 | PARAMETER is a symbol like `tramp-login-args', denoting a list of |
| 4960 | list of strings from `tramp-methods', containing %-sequences for | 4956 | list of strings from `tramp-methods', containing %-sequences for |
| 4961 | substitution. SPEC-LIST is a list of char/value pairs used for | 4957 | substitution. |
| 4962 | `format-spec-make'." | 4958 | SPEC-LIST is a list of char/value pairs used for |
| 4959 | `format-spec-make'. It is appended by `tramp-extra-expand-args', | ||
| 4960 | a connection-local variable." | ||
| 4963 | (let ((args (tramp-get-method-parameter vec parameter)) | 4961 | (let ((args (tramp-get-method-parameter vec parameter)) |
| 4964 | (spec (apply 'format-spec-make spec-list))) | 4962 | (extra-spec-list |
| 4963 | (mapcar | ||
| 4964 | #'eval | ||
| 4965 | (buffer-local-value | ||
| 4966 | 'tramp-extra-expand-args (tramp-get-connection-buffer vec)))) | ||
| 4967 | spec) | ||
| 4968 | ;; Merge both spec lists. Remove duplicate entries. | ||
| 4969 | (while spec-list | ||
| 4970 | (unless (member (car spec-list) extra-spec-list) | ||
| 4971 | (setq extra-spec-list (append (take 2 spec-list) extra-spec-list))) | ||
| 4972 | (setq spec-list (cddr spec-list))) | ||
| 4973 | (setq spec (apply #'format-spec-make extra-spec-list)) | ||
| 4965 | ;; Expand format spec. | 4974 | ;; Expand format spec. |
| 4966 | (flatten-tree | 4975 | (flatten-tree |
| 4967 | (mapcar | 4976 | (mapcar |