authors | state |
---|---|
Roman Tkachenko ([email protected]) |
implemented |
Proposes a way for users to define custom tsh commands.
Defining custom commands will allow users to extend tsh
CLI to fit their
use-case without having to modify Teleport's source code.
Examples of what users might want to do include:
-
Define shorthands for the existing
tsh
commands. -
Tweak the default behavior of existing
tsh
commands, for example to havetsh login
always default to a particular auth connector or username. -
Define new subcommands combining multiple actions in the same command, for example logging into a cluster, a database and connecting to the database.
The simplest analogue that comes to mind is the bash alias:
alias ll="ls -l"
Bash aliases are quite simplistic as they only allow to define new commands that expand to the strings they alias and don't provide a way to refer to the command's arguments.
Git aliases are defined in the repo-specific .gitconfig
(or .git/config
)
or global /etc/gitconfig
file, and are much closer conceptually to what we
want to accomplish as they allow to define custom git
subcommands:
[alias]
co = checkout
ls = log --oneline
Git aliases also support calling non-git
commands (using !
notation) and
refer to the command's arguments (via $@
, $1
, etc.) which allows to build
powerful new commands.
For example, the following alias will make git top
to show 15 most recently
updated local branches:
[alias]
top = "!bash -c 'git branch --sort=-committerdate | head -15'"
Users will define aliases in their tsh
configuration file which is kept
in $TELEPORT_HOME/config/config.yaml
using the following syntax:
aliases:
"<alias>": "<command>"
The <alias>
can only be a top-level subcommand. In other words, users can
define a new tsh mycommand
alias but cannot define tsh my command
command.
A few notes regarding the <command>
:
- Unlike
git
aliases explored above, proposal is to always require the binary name instead of defaulting totsh
and requiring special syntax otherwise. - The
<command>
will be fed toexec.Command
for execution. To chain multiple commands, use pipes, etc. users will explicitly usebash -c
. - The
<command>
will require$@
,$1
, etc. to reference the arguments provided to the alias command.
Starting with a very simple example, suppose you're tired of typing tsh login
every morning and want to alias it to something shorter e.g. tsh l
:
aliases:
"l": "tsh login $@"
As a more practical example, the following alias will make tsh login
default
to the specific auth connector and username:
aliases:
"login": "tsh login --auth=local --user=alice $@"
Similarly, as discussed in the search-based access requests RFD, some users
may want tsh ssh
to default to the mode in which it will auto-request access
to the node upon encountering an access denied error:
aliases:
"ssh": "tsh ssh -P $@"
Note: command arguments will be resolved prior to invoking the alias. So in the
example above, when a user runs tsh ssh root@node1
, the alias command executed
will be tsh ssh -P root@node1
.
Each alias invocation will set a few environment variables that can be consumed within the alias.
To prevent infinite recursion, TSH_ALIAS
variable will be set indicating the
command is invoked as an alias. If it's detected, tsh
won't attempt to expand
the same command again. For example, TSH_ALIAS=login
. This will prevent other
login
commands from being expanded but will allow using aliases in other
aliases (see below for an example).
Each alias will also set TSH
environment variable to the path of the tsh
binary that invoked the alias and SHELL
environment variable to the default
shell of the user invoking the command.
An alias can also define a custom subcommand that combines multiple commands.
The following alias will connect to a node within a specific leaf cluster
using tsh connect leaf ubuntu@node-1
command:
aliases:
"connect": "bash -c '$TSH login $1 && $TSH ssh $2'"
The following alias will list nodes in all clusters:
aliases:
"lsall": "bash -c 'for cluster in $($TSH clusters | tail -3 | head -2 | cut -d \' \' -f1); $TSH ls --cluster=$cluster; done'"
Multiple aliases can be defined in the config and can reference each other:
aliases:
"login": "$TSH login --auth=local --user=alice $@"
"ssh": "$TSH ssh -P $@"
"connect": "bash -c '$TSH login $1 && $TSH ssh $2'"
In this example, tsh login
and tsh ssh
will use the aliases when invoked
as a part of the "connect" command.
Currently tsh config is read from $TELEPORT_HOME/config/config.yaml
which by
default is user-specific since $TELEPORT_HOME
defaults to ~/.tsh
.
As a part of this feature, introduce global tsh config /etc/tsh.yaml
. Settings
from the global config will merge with the user-local config, with the local
config taking precedence.
For easier troubleshooting of aliases, make sure that tsh logs the actual command being executed when invoking an alias.
When we have bash
/zsh
auto-completion, it should take aliased commands into
account as well. For reference, git
autocompletion supports it.