How to execute script on balena ssh login to container?

I’m writing a python interactive command line interface for a device in a dedicated container and I would like to launch the .py file when I balena ssh into the container instead of having to type python script.py each. This is primarily to aid local development as I’m making that restart the container while livepush is active.

Is there an effective way to do this?

Hi Alexander! Are you looking to do something like ssh -t 'python script.py' so it runs immediately when you SSH into the container?

Hi @nucleardreamer, I was hoping to have some sort of docker file stage where I could set a default script to run when an ssh terminal is started. But this command you’re referencing is definitely a step in the right direction.

I’ve been researching adding the script to ~.bashrc as a way possible way to do this: https://superuser.com/questions/355029/how-to-automatically-run-commands-on-ssh-login/355030

It is not clear to my how to implement this in docker though as these bashrc changes will revert at on restart unless they are run from docker.

Hi @alexanderkjones, you should be able to add the python script.py command to the .bashrc of the runtime user of the service you are connecting to via SSH. The modified .bashrc should be part of the image for persistence.

If you only want to run this script when you SSH during local mode, you can set a bash condition so that it only executes when BALENA_APP_NAME=localapp.

@cmfcruz thanks so much that’s very helpful. Where can I find the ~.bashrc file? The closest I’ve been able to find is etc/bash.bashrc is this the appropriate file?

Also, @nucleardreamer I have tried the following to run the python file using balena ssh for the container cmd-shell and this does not work. I succesfully ssh into the container but nothing happens. Is there something wrong with this command: balena ssh 192.168.0.16 cmd-shell -t 'python main.py'

Thank you both for your help.

After a bit of digging on the ssh -t options I found this known issue if I’m not mistaken @nucleardreamer ?

I’ve been looking for an easy way to run scripts on ssh login and this was helpful:
Medium: Using Automator to Insert text with a Shortcut Key on Mac

I’ve been able to add shortcuts for common scripts like pytest --disable-pytest-warnings since the ssh shell does not remember previous commands in the same way basic terminal does. The challenge with testing is that the container you are testing also restarts each time you update the code or the tests, causing a loop of ssh back into the container and running the test script again. Any other insights on this appreciated.

Hi @alexanderkjones. Regarding the location of ~/.bashrc it will depend on the image configuration, but for instance for the default configuration on our debian base images, it works if you create the file under the /root folder. Modifying/etc/bash.bashrc will work too but you risk interfering with other default configurations.

With respect to the issue you link, you are correct that the only way to pass a command to balena ssh is to pipe to it or directly ssh to port 22222 (only in local mode though).

Also, if you want to ensure command history is preserved on the container shell, you could try storing the file in /root/.bash_history in a named volume so it persists even across container recreations.

Could you tell us more about what you are trying to achieve? What are you using the container for? What does the script.py file do? Does that file live on your computer or do you keep a copy on the app container?

We might be able to help you better by knowing some of this information. Thank you!

Hi @pipex thanks for all these great comments. This all makes sense given what I’ve seen.

Regarding what I’m trying to accomplish: I’m currently adding testing to a series of independent microservices written in flask running on my balena app. Using pytest I’ve found that as I am moving toward TDD practices I am having to have both livepush open in one terminal and ssh into the microservice container I am working on in another tab. Both when updating a test or updating the codebase of the microservice I am kicked out of the ssh session running the pytest command. So, my workflow tends to be save changes → livepush → restart ssh terminal → run pytest.

I’ve found that the history in the ssh terminal is flaky, I can often use the up arrow to pullup the balena ssh command, but once ssh’d in I often cannot access the history of the pytest commands I had been using. Thus, I need to retype the pytest command line which is cumbersome when I’m iterating the code at a high frequency, ie 1-2x per minute.

I had also run into this issue when building a pseudo command line tool using the python interpreter. I have built simple command shell app using the Python Interactive Console and a series of classes to hold object oriented methods to the various API endpoints I have across my application’s microservices. Again, similarly when updating the command shell code I save changes → livepush → re-ssh into the cmd-shell container → re-run my cmd-shell python script which again is not often saved in history between the ssh cycles.

So much of what I experience with balena and livepush is relatively seemless and this has just been a loud workflow issue for me. Your note about putting the bash history in a named volume sounds like it could resolve this issue. So far I’ve been relying on the custom keyboard shortcuts to paste pre-defined commandlines such a pytest --nowarnings --cov=src etc.

I’m primarily using the balenalib/fincm3-python:3.8-run for most of my containers. Could you tell me how I could adjust my docker file to store .bash_history in a named volume?

Hi,

I feel like you’re trying to do with your .bash_history what I’ve done with my .ssh directory (to keep keys/known hosts the same between updates).
What I did was to add a check in the script executed by my container.
In this script, I move the existing .ssh directory to my persistent data and create a symlink to it if necessary.


PERS_SSH_DIR="/data/.ssh"
TRANS_SSH_DIR="/root/.ssh"

# Setup persistent SSH directory and generate new SSH key
if [[ ! -d "${PERS_SSH_DIR}" ]]; then
        mkdir -p "${PERS_SSH_DIR}"
        ssh-keygen -q -t rsa -b 4096 -N "" -f "${PERS_SSH_DIR}/id_rsa"
fi

# If transient SSH dir is not a link, move contents and replace it
if [[ ! -L "${TRANS_SSH_DIR}" ]]; then
        if [[ -e "${TRANS_SSH_DIR}" ]]; then
                mv "${TRANS_SSH_DIR}"/* "${PERS_SSH_DIR}"
                rm -rf "${TRANS_SSH_DIR}"
        fi


        # Link to persistent directory
        ln -s "${PERS_SSH_DIR}" "${TRANS_SSH_DIR}"
fi

This will probably also work for single files like .bash_history (replacing the directory with file operations).
Do keep in mind that .bash_history can still act a little weird if you have multiple logins going.
It’s better to store often used commands in scripts than to rely on having it in your history.

I would also like to point out that bash history is kept in memory for the duration of your session.
You may need to issue a history -a command to append your current session to the history file.

@alexanderkjones we found your question very interesting and ended up covering it on a recent IoT Project Clinic:

Hope this help! If you have any more questions, let us know!

Thanks for posting this so cool to see and great nuggets in there!

I would say after trying a couple things in practice here for anyone following along using the custom hot keys for pasting text as I described in the previous comment above has been the most successful when repeatedly running the same command for a test suite or to open a cli once I’ve ssh’d into the container.

This has definitely sped up my workflow. An alternative method, specifically for testing, could be to have the tests run as my entry point during development but I’m not as familiar on how to orchestrate that. Thanks all for your advice on this topic!

Give us a ping if you have any other questions that might make a good segment for the show @alexanderkjones . :wink: