aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2023-06-23 21:26:14 +0200
committerMichael Albinus2023-06-23 21:26:14 +0200
commit77c2f05d773271cb59ebfd994b06a4075cacbfa8 (patch)
tree44840ebc7831e8041c464f61fe094df95ed0a4b5
parent1c499c18afd6a709272fe60a540a27093e589fff (diff)
downloademacs-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.texi11
-rw-r--r--etc/NEWS8
-rw-r--r--lisp/net/tramp-container.el145
-rw-r--r--lisp/net/tramp-sh.el10
-rw-r--r--lisp/net/tramp.el29
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
924Integration for containers in Kubernetes pods. The host name is a pod 924Integration for containers in Kubernetes pods. The host name is a pod
925name returned by @samp{kubectl get pods}. The first container in a 925name returned by @samp{kubectl get pods}, or
926pod is used. 926@samp{@var{container}.@var{pod}} if an explicit container name shall
927be used. Otherwise, the first container in a pod is used.
928
929@vindex tramp-kubernetes-context
930@vindex tramp-kubernetes-namespace
931If another Kubernetes context or namespace shall be used, configure
932the user options @code{tramp-kubernetes-context} and
933@code{tramp-kubernetes-namespace}.
927 934
928This method does not support user names. 935This method does not support user names.
929 936
diff --git a/etc/NEWS b/etc/NEWS
index 88d432960f3..467ac3ee587 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -225,6 +225,14 @@ They allow accessing system containers provided by Toolbox or
225sandboxes provided by Flatpak. 225sandboxes provided by Flatpak.
226 226
227+++ 227+++
228*** Connection method "kubernetes" supports now optional container name.
229The host name for Kubernetes connections can be of kind [CONTAINER.]POD,
230in order to specify a dedicated container. If there is just the pod
231name, the first container in the pod is taken. The new user options
232'tramp-kubernetes-context' and 'tramp-kubernetes-namespace' allow to
233access 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'.
229The old name still exists as obsolete variable alias. This user 237The old name still exists as obsolete variable alias. This user
230option controls now connection sharing for both ssh-based and 238option 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.
112If 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
172see its function help for a description of the format." 187see 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.
234Obey `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.
4329It should return a string which is used to check, whether the
4330configuration of the remote host has been changed (which would
4331require to flush the cache data). This string is kept as
4332connection property \"config-check-data\".
4333This 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.
4329Mainly sets the prompt and the echo correctly. PROC is the shell 4337Mainly 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'.
4959PARAMETER is a symbol like `tramp-login-args', denoting a list of 4955PARAMETER is a symbol like `tramp-login-args', denoting a list of
4960list of strings from `tramp-methods', containing %-sequences for 4956list of strings from `tramp-methods', containing %-sequences for
4961substitution. SPEC-LIST is a list of char/value pairs used for 4957substitution.
4962`format-spec-make'." 4958SPEC-LIST is a list of char/value pairs used for
4959`format-spec-make'. It is appended by `tramp-extra-expand-args',
4960a 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