Skip to content

tecracer-chef/trainsh

Repository files navigation

TrainSH

Summary

Interactive Shell for Remote Systems

Based on the Train ecosystem, provide a shell to manage systems via a multitude of transports.

Train default supports:

  • Docker
  • Local
  • SSH (Unix, Windows, Cisco)
  • WinRM (Windows)

3rd party plugins support:

  • AWS Systems Manager
  • LXD
  • Telnet
  • Serial/USB interfaces
  • VMware Guest Operations (VMware Tools)
  • ...

Example uses

When specifying a password within an URL take care of special characters or the connection will fail.

trainsh connect local://
trainsh connect winrm://Administrator:Passw0rd@10.20.30.40
trainsh connect awsssm://i-123456789abc0
trainsh connect vsphere-gom://example-vm

If the transport has additional options like key_files, they need to be added as URL parameters (ssh://10.20.30.40/?key_files=~/.ssh/id_rsa2).

Shell commands

There are three separate categories of commands when in the Shell:

  • remote commands
  • local commands, which are prefixed with .
  • built-in commands, wich are prefixed with !

Anything you type without a prefix gets executed 1:1 on the remote system. Please notice that Train is headless, so any interactive programs will not work but lock up your shell! If you need to edit remote files or use a pager (like less), please look into the Built-In Commands section.

Local commands get executed 1:1 on your local system, so you are able to check things locally or change paths, for example.

There is also the Sessionprefix @, which is described briefly in the "Prompt and Sessions" section.

Built-In Commands

!!! Quit TrainSH. Aliases: quit, exit, logout, disconnect.

!clear-history Clear your TrainSH history, for example to remove clutter or sensitive information

!connect <uri> Connect to another system. The URI needs to match the format of the used Train transport, which is usually transportname://host but varies. See the Train transport's documentation for details.

!copy @<session>:/<path> @<session>:/<path> Copy a file between two established sessions.

!detect Re-runs the OS detection which is running automatically on start. This will determine the OS, OS-family and general platform information via Train.

!download <remote> <local> Download a file to the local system. You need to specify the target, if you want to keep the name just use . as local part.

!edit <remotefile> Downloads the remote file as temporary file and opens the system default editor locally (EDITOR and VISUAL environment variables, with fallback to vi). Upon exiting the file, it will be uploaded again and overwrite the remote file.

!env Prints the environment variables of your remote shell. This will be filled on first command invocation to save IO. Currently unsupported for Windows remote systems

!help Print out help

!history Output your TrainSH command history. As this uses the popular Readline library, you can also navigate your history with the Up/Down arrows or use Ctrl-R for reverse search. You can do auto completion for built-in commands.

!host Outputs the remote hostname.

!ping Executes a simple command to measure roundtrip/overhead time.

!pwd Output the remote working directory. This will be filled on first command invocation to save IO.

!read <remotefile> Download the specified file and display it in the system default pager (PAGER environment variable, with fallback to less).

!reconnect Quits and reopens the current session.

!sessions List all currently active sessions (See "Prompt and Sessions" section). Password information is redacted for security reasons.

!session <session_id> Change to another session by passing its ID (=number)

!upload <local> <remote> Upload files to the target machine

Prompt and Sessions

OK trainsh(@0 local://trc4023)>

The prompt consists roughly of three areas:

  • Exit code of last command ("OK" or the exit code in format Exx with xx being the numeric code)
  • Session indication
  • Input area

The session indication includes the ID of the session, so @0 means session 0, @1 means session 1 and so on. The second part shows the Train URI for the remote system for easy identification.

Any TrainSH invocation has at minimum one active session but if you want, you can add more sessions with the !connect <uri> built-in. Every session has its own Train backend and storage of current working directory, environment variables etc. You can list active sessions with !sessions and switch between them using !session <session_id>.

If you want to execute commands on another session ad-hoc, you can prefix it with the session id: @1 uname -a will execute the uname -a command on session ID 1.

Depending on the transport and target, the time between sending a command and retrieving the result will vary widely. In TrainSH this is called the "ping", which measures the minimum overhead/latency for the session. It varies massively between Train plugins and is not only related to the network distance, but also to the way of command execution - which might involve a number of HTTPS requests or the time to invoke a remote shell (examples: AWS SSM and VSphere GOM transports).

Under the Hood

As Train is headless/stateless system, there will be various pre- and postfixed commands to make your life easier. This means that any state-related commands like changing the current directory or modification of environment variables would be unavailable for the next command - as it technically is a separate shell.

To make this easier, internal commands get attached to your input like this:

  • Prefix: Get remote hostname (discovery task, just on first execution)
  • Prefix: Set previous environment variables
  • Prefix: Set previous path
  • Command
  • Postfix: Retrieve and save exit code of command
  • Postfix: Retrieve and save new path
  • Postfix: Retrieve and save new environment variables

Output of commands gets separated by outputting a highly random string between, which should not result in false positives. If a false positive occurs for some reason, TrainSH will fail and output an error.

Target Detection

As providing target URLs to connect to can be tedious, TrainSH will detect targets to connect to via plugins. In these cases, trainsh connect does not need any parameters.

Environment Variables

This will check the TARGET environment variable for a URL and use it to connect. Only one target is allowed.

Test Kitchen Configuration

This will detect if the current directory has a Test Kitchen configuration and a created machine. If so, it will connect to the machine by parsing information in .kitchen/ and the kitchen configuration file.