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.
This commit is contained in:
@@ -922,8 +922,15 @@ if desired.
|
||||
@cindex @option{kubernetes} method
|
||||
|
||||
Integration for containers in Kubernetes pods. The host name is a pod
|
||||
name returned by @samp{kubectl get pods}. The first container in a
|
||||
pod is used.
|
||||
name returned by @samp{kubectl get pods}, or
|
||||
@samp{@var{container}.@var{pod}} if an explicit container name shall
|
||||
be used. Otherwise, the first container in a pod is used.
|
||||
|
||||
@vindex tramp-kubernetes-context
|
||||
@vindex tramp-kubernetes-namespace
|
||||
If another Kubernetes context or namespace shall be used, configure
|
||||
the user options @code{tramp-kubernetes-context} and
|
||||
@code{tramp-kubernetes-namespace}.
|
||||
|
||||
This method does not support user names.
|
||||
|
||||
|
||||
8
etc/NEWS
8
etc/NEWS
@@ -224,6 +224,14 @@ point is not in a comment or a string. It is by default bound to
|
||||
They allow accessing system containers provided by Toolbox or
|
||||
sandboxes provided by Flatpak.
|
||||
|
||||
+++
|
||||
*** Connection method "kubernetes" supports now optional container name.
|
||||
The host name for Kubernetes connections can be of kind [CONTAINER.]POD,
|
||||
in order to specify a dedicated container. If there is just the pod
|
||||
name, the first container in the pod is taken. The new user options
|
||||
'tramp-kubernetes-context' and 'tramp-kubernetes-namespace' allow to
|
||||
access pods with different context or namespace but the default one.
|
||||
|
||||
+++
|
||||
*** Rename 'tramp-use-ssh-controlmaster-options' to 'tramp-use-connection-share'.
|
||||
The old name still exists as obsolete variable alias. This user
|
||||
|
||||
@@ -37,19 +37,20 @@
|
||||
;; C-x C-f /podman:USER@CONTAINER:/path/to/file
|
||||
;;
|
||||
;; Where:
|
||||
;; USER is the user on the container to connect as (optional)
|
||||
;; CONTAINER is the container to connect to
|
||||
;; USER is the user on the container to connect as (optional).
|
||||
;; CONTAINER is the container to connect to.
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; Open file in a Kubernetes container:
|
||||
;;
|
||||
;; C-x C-f /kubernetes:POD:/path/to/file
|
||||
;; C-x C-f /kubernetes:[CONTAINER.]POD:/path/to/file
|
||||
;;
|
||||
;; Where:
|
||||
;; POD is the pod to connect to.
|
||||
;; By default, the first container in that pod will be
|
||||
;; used.
|
||||
;; POD is the pod to connect to.
|
||||
;; CONTAINER is the container to connect to (optional).
|
||||
;; By default, the first container in that pod will
|
||||
;; be used.
|
||||
;;
|
||||
;; Completion for POD and accessing it operate in the current
|
||||
;; namespace, use this command to change it:
|
||||
@@ -63,7 +64,7 @@
|
||||
;; C-x C-f /toolbox:CONTAINER:/path/to/file
|
||||
;;
|
||||
;; Where:
|
||||
;; CONTAINER is the container to connect to (optional)
|
||||
;; CONTAINER is the container to connect to (optional).
|
||||
;;
|
||||
;; If the container is not running, it is started. If no container is
|
||||
;; specified, the default Toolbox container is used.
|
||||
@@ -106,6 +107,20 @@
|
||||
:type '(choice (const "kubectl")
|
||||
(string)))
|
||||
|
||||
(defcustom tramp-kubernetes-context nil
|
||||
"Context of Kubernetes.
|
||||
If it is nil, the default context will be used."
|
||||
:group 'tramp
|
||||
:version "30.1"
|
||||
:type '(choice (const :tag "Use default" nil)
|
||||
(string)))
|
||||
|
||||
(defcustom tramp-kubernetes-namespace "default"
|
||||
"Namespace of Kubernetes."
|
||||
:group 'tramp
|
||||
:version "30.1"
|
||||
:type 'string)
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defcustom tramp-toolbox-program "toolbox"
|
||||
"Name of the Toolbox client program."
|
||||
@@ -172,29 +187,83 @@ This function is used by `tramp-set-completion-function', please
|
||||
see its function help for a description of the format."
|
||||
(when-let ((default-directory tramp-compat-temporary-file-directory)
|
||||
(raw-list (shell-command-to-string
|
||||
(concat tramp-kubernetes-program
|
||||
" get pods --no-headers "
|
||||
"-o custom-columns=NAME:.metadata.name")))
|
||||
(names (split-string raw-list "\n" 'omit)))
|
||||
(mapcar (lambda (name) (list nil name)) (delq nil names))))
|
||||
(concat
|
||||
tramp-kubernetes-program " "
|
||||
(tramp-kubernetes--context-namespace nil)
|
||||
" get pods --no-headers"
|
||||
;; We separate pods by "|". Inside a pod,
|
||||
;; its name is separated from the containers
|
||||
;; by ":". Containers are separated by ",".
|
||||
" -o jsonpath='{range .items[*]}{\"|\"}{.metadata.name}"
|
||||
"{\":\"}{range .spec.containers[*]}{.name}{\",\"}"
|
||||
"{end}{end}'")))
|
||||
(lines (split-string raw-list "|" 'omit)))
|
||||
(let (names)
|
||||
(dolist (line lines)
|
||||
(setq line (split-string line ":" 'omit))
|
||||
;; Pod name.
|
||||
(push (car line) names)
|
||||
;; Container names.
|
||||
(dolist (elt (split-string (cadr line) "," 'omit))
|
||||
(push (concat elt "." (car line)) names)))
|
||||
(mapcar (lambda (name) (list nil name)) (delq nil names)))))
|
||||
|
||||
(defconst tramp-kubernetes--host-name-regexp
|
||||
(rx (? (group (regexp tramp-host-regexp)) ".")
|
||||
(group (regexp tramp-host-regexp)))
|
||||
"The CONTAINER.POD syntax of kubernetes host names in Tramp.")
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defun tramp-kubernetes--container (vec)
|
||||
"Extract the container name from a kubernetes host name in VEC."
|
||||
(or (let ((host (tramp-file-name-host vec)))
|
||||
(and (string-match tramp-kubernetes--host-name-regexp host)
|
||||
(match-string 1 host)))
|
||||
""))
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defun tramp-kubernetes--pod (vec)
|
||||
"Extract the pod name from a kubernetes host name in VEC."
|
||||
(or (let ((host (tramp-file-name-host vec)))
|
||||
(and (string-match tramp-kubernetes--host-name-regexp host)
|
||||
(match-string 2 host)))
|
||||
""))
|
||||
|
||||
(defun tramp-kubernetes--current-context (vec)
|
||||
"Return Kubernetes current context.
|
||||
Obey `tramp-kubernetes-context'"
|
||||
(or tramp-kubernetes-context
|
||||
(with-tramp-connection-property nil "current-context"
|
||||
(with-temp-buffer
|
||||
(when (zerop
|
||||
(tramp-call-process
|
||||
vec tramp-kubernetes-program nil t nil
|
||||
"config" "current-context"))
|
||||
(goto-char (point-min))
|
||||
(buffer-substring (point) (line-end-position)))))))
|
||||
|
||||
(defun tramp-kubernetes--current-context-data (vec)
|
||||
"Return Kubernetes current context data as JSON string."
|
||||
(with-temp-buffer
|
||||
(when (zerop
|
||||
(tramp-call-process
|
||||
vec tramp-kubernetes-program nil t nil
|
||||
"config" "current-context"))
|
||||
(goto-char (point-min))
|
||||
(let ((current-context (buffer-substring (point) (line-end-position))))
|
||||
(erase-buffer)
|
||||
(when (zerop
|
||||
(tramp-call-process
|
||||
vec tramp-kubernetes-program nil t nil
|
||||
"config" "view" "-o"
|
||||
(format
|
||||
"jsonpath='{.contexts[?(@.name == \"%s\")]}'" current-context)))
|
||||
(buffer-string))))))
|
||||
(when-let ((current-context (tramp-kubernetes--current-context vec)))
|
||||
(with-temp-buffer
|
||||
(when (zerop
|
||||
(tramp-call-process
|
||||
vec tramp-kubernetes-program nil t nil
|
||||
"config" "view" "-o"
|
||||
(format
|
||||
"jsonpath='{.contexts[?(@.name == \"%s\")]}'" current-context)))
|
||||
(buffer-string)))))
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defun tramp-kubernetes--context-namespace (vec)
|
||||
"The kubectl options for context and namespace."
|
||||
(mapconcat
|
||||
#'identity
|
||||
`(,(when-let ((context (tramp-kubernetes--current-context vec)))
|
||||
(format "--context=%s" context))
|
||||
,(when tramp-kubernetes-namespace
|
||||
(format "--namespace=%s" tramp-kubernetes-namespace)))
|
||||
" "))
|
||||
|
||||
;;;###tramp-autoload
|
||||
(defun tramp-toolbox--completion-function (&rest _args)
|
||||
@@ -275,12 +344,13 @@ see its function help for a description of the format."
|
||||
(add-to-list 'tramp-methods
|
||||
`(,tramp-kubernetes-method
|
||||
(tramp-login-program ,tramp-kubernetes-program)
|
||||
(tramp-login-args (("exec")
|
||||
(tramp-login-args (("%x") ; context and namespace.
|
||||
("exec")
|
||||
("-c" "%a") ; container.
|
||||
("%h")
|
||||
("-it")
|
||||
("--")
|
||||
("%l")))
|
||||
(tramp-config-check tramp-kubernetes--current-context-data)
|
||||
(tramp-direct-async (,tramp-default-remote-shell "-c"))
|
||||
(tramp-remote-shell ,tramp-default-remote-shell)
|
||||
(tramp-remote-shell-login ("-l"))
|
||||
@@ -334,6 +404,23 @@ see its function help for a description of the format."
|
||||
|
||||
;; Default connection-local variables for Tramp.
|
||||
|
||||
(defconst tramp-container-connection-local-default-kubernetes-variables
|
||||
'((tramp-config-check . tramp-kubernetes--current-context-data)
|
||||
;; This variable will be eval'ed in `tramp-expand-args'.
|
||||
(tramp-extra-expand-args
|
||||
. (?a (tramp-kubernetes--container (car tramp-current-connection))
|
||||
?h (tramp-kubernetes--pod (car tramp-current-connection))
|
||||
?x (tramp-kubernetes--context-namespace (car tramp-current-connection)))))
|
||||
"Default connection-local variables for remote kubernetes connections.")
|
||||
|
||||
(connection-local-set-profile-variables
|
||||
'tramp-container-connection-local-default-kubernetes-profile
|
||||
tramp-container-connection-local-default-kubernetes-variables)
|
||||
|
||||
(connection-local-set-profiles
|
||||
`(:application tramp :protocol ,tramp-kubernetes-method)
|
||||
'tramp-container-connection-local-default-kubernetes-profile)
|
||||
|
||||
(defconst tramp-container-connection-local-default-flatpak-variables
|
||||
`((tramp-remote-path . ,(cons "/app/bin" tramp-remote-path)))
|
||||
"Default connection-local variables for remote flatpak connections.")
|
||||
|
||||
@@ -4324,6 +4324,14 @@ seconds. If not, it produces an error message with the given ERROR-ARGS."
|
||||
(apply #'tramp-error-with-buffer
|
||||
(tramp-get-connection-buffer vec) vec 'file-error error-args)))))
|
||||
|
||||
(defvar tramp-config-check nil
|
||||
"A function to be called with one argument, VEC.
|
||||
It should return a string which is used to check, whether the
|
||||
configuration of the remote host has been changed (which would
|
||||
require to flush the cache data). This string is kept as
|
||||
connection property \"config-check-data\".
|
||||
This variable is intended as connection-local variable.")
|
||||
|
||||
(defun tramp-open-connection-setup-interactive-shell (proc vec)
|
||||
"Set up an interactive shell.
|
||||
Mainly sets the prompt and the echo correctly. PROC is the shell
|
||||
@@ -4370,7 +4378,7 @@ process to set up. VEC specifies the connection."
|
||||
vec "uname"
|
||||
(tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))))
|
||||
(config-check-function
|
||||
(tramp-get-method-parameter vec 'tramp-config-check))
|
||||
(buffer-local-value 'tramp-config-check (process-buffer proc)))
|
||||
(old-config-check
|
||||
(and config-check-function
|
||||
(tramp-get-connection-property vec "config-check-data")))
|
||||
|
||||
@@ -300,13 +300,6 @@ pair of the form (KEY VALUE). The following KEYs are defined:
|
||||
and container methods do. If it is a list of strings, they
|
||||
are used to construct the remote command.
|
||||
|
||||
* `tramp-config-check'
|
||||
A function to be called with one argument, VEC. It should
|
||||
return a string which is used to check, whether the
|
||||
configuration of the remote host has been changed (which
|
||||
would require to flush the cache data). This string is kept
|
||||
as connection property \"config-check-data\".
|
||||
|
||||
* `tramp-copy-program'
|
||||
This specifies the name of the program to use for remotely copying
|
||||
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'.")
|
||||
;; Result.
|
||||
target-alist))
|
||||
|
||||
(defvar tramp-extra-expand-args nil
|
||||
"Method specific arguments.")
|
||||
|
||||
(defun tramp-expand-args (vec parameter &rest spec-list)
|
||||
"Expand login arguments as given by PARAMETER in `tramp-methods'.
|
||||
PARAMETER is a symbol like `tramp-login-args', denoting a list of
|
||||
list of strings from `tramp-methods', containing %-sequences for
|
||||
substitution. SPEC-LIST is a list of char/value pairs used for
|
||||
`format-spec-make'."
|
||||
substitution.
|
||||
SPEC-LIST is a list of char/value pairs used for
|
||||
`format-spec-make'. It is appended by `tramp-extra-expand-args',
|
||||
a connection-local variable."
|
||||
(let ((args (tramp-get-method-parameter vec parameter))
|
||||
(spec (apply 'format-spec-make spec-list)))
|
||||
(extra-spec-list
|
||||
(mapcar
|
||||
#'eval
|
||||
(buffer-local-value
|
||||
'tramp-extra-expand-args (tramp-get-connection-buffer vec))))
|
||||
spec)
|
||||
;; Merge both spec lists. Remove duplicate entries.
|
||||
(while spec-list
|
||||
(unless (member (car spec-list) extra-spec-list)
|
||||
(setq extra-spec-list (append (take 2 spec-list) extra-spec-list)))
|
||||
(setq spec-list (cddr spec-list)))
|
||||
(setq spec (apply #'format-spec-make extra-spec-list))
|
||||
;; Expand format spec.
|
||||
(flatten-tree
|
||||
(mapcar
|
||||
|
||||
Reference in New Issue
Block a user