Hello Michael, all,
I have a use case that I couldn't find a clean solution for, and I'm
wondering if Tramp could provide a nicer way to handle it.
In Kubed[0], we define a Tramp method called "kubedv2", which uses
kubectl to interact with Kubernetes workloads, somewhat similarly to the
"kubernetes" method from tramp-container.el. Following a feature
request from a user, we want the "kubedv2" method to work in multi-hop
settings, in which the user uses Tramp to connect to some remote host,
say via ssh, and then from that remote host they invoke a Kubed command
that starts a two-hop Tramp connection using ssh for the first hop and
kubedv2 for the second.
The difficulty is that on the remote host (the target of the ssh
connection), the user may need to specify a different kubectl executable
to use as the tramp-login-program. Kubed lets you specify which kubectl
to use through a user option kubed-kubectl-program, and we always use
the connection-local value of that variable so users can configure
different kubectl to use on different hosts, but that doesn't naturally
extend to our Tramp method, because the tramp-login-program is always
taken from the specific value we put in tramp-methods when "defining"
the method.
Indeed, AFAICT, all Tramp methods essentially hardcode the
tramp-login-program value, which in particular cannot vary based on
connection-local variables when used in multi-hop settings. For
example, in tramp-enable-toolbox-method we have:
(add-to-list 'tramp-methods
`(,tramp-toolbox-method
(tramp-login-program ,tramp-toolbox-program)
...))
So the specific value that tramp-toolbox-program has when
tramp-enable-toolbox-method is called becomes hardcoded in tramp-methods.
WDYT about generalizing the tramp-login-program entry of tramp-methods
such that it will allow a function value, instead of a string, which
will be able to take into account previous hops to compute the right
string value? So something like this:
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 5441a26d7a0..c165b62aa33 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -5446,6 +5446,8 @@ tramp-handle-make-process
command))
(login-program
(tramp-get-method-parameter v 'tramp-login-program))
+ (login-program
+ (if (functionp login-program) (funcall login-program v)
login-program))
;; We don't create the temporary file. In fact, it is just
;; a prefix for the ControlPath option of ssh; the real
;; temporary file has another name, and it is created and
Currently, our workaround in Kubed is to install an advice around
tramp-get-method-parameter so it DTRT for multi-hop kubedv2 connections:
(defun kubed-tramp-get-method-parameter-advice
(of vec param &rest rest)
"Respect connection-local value of `kubed-kubectl-program'."
(if (and (eq param 'tramp-login-program)
(equal (tramp-file-name-method vec) kubed-tramp-method))
;; 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'.
(if-let ((hop (tramp-file-name-hop vec)))
(let ((default-directory
(tramp-make-tramp-file-name
(tramp-dissect-hop-name (tramp-file-name-hop vec)))))
(connection-local-value kubed-kubectl-program 'kubed))
kubed-kubectl-program)
(apply of vec param rest)))
Is there a better (or just more officially supported) approach that you
would recommend?
Thanks,
Eshel
[0] Git repo available from any of the following:
https://git.sr.ht/~eshel/kubed
https://github.com/eshelyaron/kubed/
git://git.eshelyaron.com/kubed.git