Creating a custom launcher to run a terminal with a specific command

I would like to add a launcher to the list of launchers available from the “+” button in JupyterLab which opens a terminal, like the existing Terminal launcher does, but runs a custom command. The command for the launcher should be configured on the server. Is this possible?

My use case is that I want to allow users to run JupyterLab on the login node of an HPC cluster, and click a button to launch a terminal with a shell in an interactive job on a compute node.

A potentially useful tack might be jupyter_app_launcher.

I’m not sure how you’d tie that into the Terminal activity right now though, however.

Thanks! That is definitely a good piece of the puzzle to find. I also found this,

which allows you to change the shell used, but probably not on a per-launcher basis. The “shell” could presumably be bash with some options to run a startup file which was the command I need. But can this be adapted to choose the shell based on which launcher was used? The terminal functionality doesn’t seem well documented, or is maybe just very focused on doing one thing well (allowing an ssh-like login to the server).

Yep. The REST/WebSocket implementation is actually in jupyter_server_terminals, while the actual terminal part is in terminado.

I’m not sure how deep one would have to go: it seems like potentially creating an overloading wrapper for the serverextension that started the terminal as usual, then ran some SSH commands might work, and is reasonable on your system.

There was the ability to pre-run commands in terminals in lab, but this was just too delicious a target for the general case… that would be another approach altogether, if something like this existed… but there’s certainly a good reason to not encourage arbitrary automatic remote execution by default.

1 Like

Thanks for all the pointers. So it looks like the ability to run a per-launcher custom command in a Terminal is not implemented.

[rolls up sleeves]

For my use case, it is probably enough at the moment to be able to provide a predefined list of shells in the server config, e.g.

shells_available = 
  {"bash": {"exec": "/bin/bash"},
   "interactive_job": {"exec": "qlogin"}

and to implement some way to pass this information from a launcher. A shell name could be passed through the API. Given a fixed list of terminal commands without parameters makes it fairly easy for the admin to secure. Even allowing parameters to be passed (in my case, the number of CPUs to request for the interactive job) might be limited enough to be safe.

For a quick and probably insecure implementation, it actually looks like any data in the POST /api/terminals is eventually fed through to the terminado terminal as kwargs when it is created, so just modifying the openapi schema to allow “shell” would probably have the desired effect, at the cost of allowing arbitrary commands to be executed on your server… Instead we could convert a “shell_id” from bash/qlogin etc to the command to run before passing it on as “shell”.

What is the security issue with allowing the launcher to determine the command? Notebook users can run arbitrary commands anyway. Is it that this would run on the server rather than in a kernel (which might not be on the same machine, or might be in an isolated environment)?

Where is the Terminal launcher defined? I expected it to be defined somewhere in jupyter_server_terminals, but a grep for “launcher” returns no hits there.