Attach and run script inside an existing tmux session - bash

I want to have more control over a time consuming cron job running on a server. That is, be able to see progress, stop running code if necessary and etc..
I thought that this would be possible using a tmux session, but I can not figure out how.
I know that you can start new tmux sessions and run code inside it like this:
tmux new-session -d -s session_name "some code"
I've tried the obvious solution like this:
tmux new-session -s session_name
**exit session**
tmux a -t session_name "some code"
Is this even possible? Any advice is appreciated.

You could send the key to the tmux session:
tmux send -t session_name ls ENTER
if you need to send to a specific panel:
tmux send -t session_name.(panelnumber) ls ENTER
example:
tmux send -t session_name.0 ls ENTER

Related

Making an app using ssh to shutdown macbook

I have been trying to create an app that can shutdown my mac using ssh. I've tried ssh-copy-id -i ~/.ssh./id_rsa.pub ssh "my computer" | sudo shutdown -h now but I get an error message saying zsh:exit 1 and zsh: suspended (tty output) sudo shutdown -h now and I don't know what to do.
There are several issues with your command:
ssh-copy-id -i ~/.ssh./id_rsa.pub ssh "my computer" | sudo shutdown -h now
That's two commands. You need a semicolon or line break to separate them
ssh-copy-id needs the private key, but you've provided the public key
That key looks like it has an extra dot in the key path
You're running sudo shutdown -h now locally rather than remotely
Run this just one time. It will prompt you for your user's password on mycomputer:
ssh-copy-id -i ~/.ssh/id_rsa mycomputer
Then you can run this:
ssh -t mycomputer "sudo shutdown -h now"
This will be interactive since you need to enter your user password for sudo, but at least the key prevents you from needing to enter it a second time to gain access to the system.
You could reduce this by allowing your user to run that command without a password. From a shell on that computer (ssh mycomputer), run visudo (if the last line of that file looks like #includedir /etc/sudoers.d, quit and run something like visudo -f /etc/sudoers.d/local) and add this to the end:
gjwlsdnd224 ALL=(root) NOPASSWD: /sbin/shutdown -h now
where gjwlsdnd224 is your username. If you do this, you don't need -t passed to ssh.

running a server in tmux with ansible

trying to setup a staging server for an API which I'm building using Django - and so far I was cutting corners, starting the thing using python manage.py runserver. But now that the setup grew a bit more complex, I decided to build an ansible playbok. Everything worked fine until I got to launching gunicorn - because I want it to run inside a tmux session. Manual process doesn't seem to trivially translate to ansible. I've been manually creating tmux session:
tmux new-session -A -s api
and then running gunicorn inside this new "environment" (subshell?)
The thing is (as is probably obvious to ansible veterans), when I get to running the first step, my playbook just hangs, and never gets to the next step, which is where gunicorn is to be started. I suppose this is because I'm starting a new shell with tmux, and ansible is lost, not hearing back (because, my guess, it's still waiting for a response on the original shell? which will never come). Is there a right way to execute the "tmux" step, letting ansible use it as a context/environment for the next step, or should I just be content with ansible doing the setup, and do the tmux thing manually? I had a similar problem, when dealing with the fact that gunicorn is inside a virtualenv, but the workaround is to use a full path, which includes the virtualenv guts. Not sure if there's a similar workaround with tmux...
thanks y'all
tmux immediately attaches to the new session, and doesn't exit until you detach from the session or the last process in the session ends. Until tmux exits, the rest of your script hangs.
You can use the -D option to prevent attaching to the session, whether or not it needs to be created.
tmux new-session -AD -s api
The rest of your script can now proceed.
tmux new-session -AD -s api is a shortcut for
tmux has-session -t api || tmux new-session -d -s api

Tmux restore creates an empty session

I'm using the tmux-continuum and tmux-resurrect plugins. If I kill tmux (restarting my machine for example) and then run the following commands:
$ tmux ls
$ failed to connect to server: No such file or directory
Then when I start tmux it automatically restores my saved sessions plus an unnamed session (usually 0)
$ tmux
$ tmux ls
0: 1 windows (created...)
saved_session_1: 1 windows (created...)
saved_session_2: 1 windows (created...)
...
My current workflow goes like this:
Start tmux
Detach from tmux
Attach to the unnamed session
Kill unnamed session
Attach to one of my saved sessions
I don't want to have to repeat this every time I restart tmux. How can I restore my saved tmux sessions without creating the unnamed session?
If I understand correctly your question this is a common issue with tmux-resurrect. The solution given here (currently the last comment in the Github discussion) has worked for me.
Add the following to your .tmux.conf and then do source ~.tmux.conf(if that is the path of your conf file):
set -g #resurrect-hook-pre-restore-pane-processes 'tmux switch-client -n && tmux kill-session -t=0'
This a hook for tmux-resurrect which tells it to kill session 0 before restoring the panels.
Note: since the name of the session (-t=0) is hardcoded it will work only for that session, hence only if you do restore when you start the tmux server the first time, if you restore from sessions after 0 nothing will happen (which is nice to avoid kill sessions accidentally).
Run the following command (preferably make an alias it):
$ tmux new-session -A -s [session-name]
Flag meaning:
-s refers to session name.
-A In case session-name exists, command will act like attach-session instead of new-session.
Refer to the man page for official documentation:
$ man tmux
new-session [-AdDEP] [-c start-directory] [-F format] [-n window-name] [-s session-name] [-t
target-session] [-x width] [-y height] [shell-command]
(alias: new)
Create a new session with name session-name.
The new session is attached to the current terminal unless -d is given. window-name and
shell-command are the name of and shell command to execute in the initial window. If -d
is used, -x and -y specify the size of the initial window (80 by 24 if not given).
If run from a terminal, any termios(4) special characters are saved and used for new win‐
dows in the new session.
The -A flag makes new-session behave like attach-session if session-name already exists;
in this case, -D behaves like -d to attach-session.
If -t is given, the new session is grouped with target-session. This means they share
the same set of windows - all windows from target-session are linked to the new session,
any new windows are linked to both sessions and any windows closed removed from both ses‐
sions. The current and previous window and any session options remain independent and
either session may be killed without affecting the other. -n and shell-command are
invalid if -t is used.
The -P option prints information about the new session after it has been created. By
default, it uses the format ‘#{session_name}:’ but a different format may be specified
with -F.
If -E is used, the update-environment option will not be applied.
You could simply launch tmux by tmux a (i.e. attach to "existing" sessions). This would trigger tmux-continuum to first restore all sessions and then you'll get attached to one of them.
Works fine for me. I'm running tmux 3.0a with tmux-resurrect and tmux-continuum plugins.

Running ssh sudo asynchronously

I'm trying to run a command with sudo on a remote machine. When I do it directly with
ssh -t -t -t myserver -q "sudo otheruser<<EOF
remotescript.sh
EOF"
it works fine, but if I add & at the end of the last line then it doesn't work. Why? How can I make it work?
I fact I'm running several such commands (to different servers) from a local script and save each output in a different file and would like them to run asynchronously.
Note: running ssh with otheruser#myserver is not an option. I really need to run sudo after I logged in.
Remove requiretty from sudo config (/etc/sudoers) on the remote machine.
Also add the -f option to ssh which puts the command in background (man: "must be used when ssh is run in the background").
The "&" should not be needed when using -f.
E.g:
ssh -f -t -t -t myserver -q "sudo otheruser<<EOF
remotescript.sh
EOF"
Use expect to control your ssh. It could be used to give automated response to the remote shell. Most processes when ran asynchronously suspends itself or becomes suspended when it tries to read input from terminal since another foreground process (the main shell) is using it.
There's a post about ssh and expect lately here: https://superuser.com/questions/509545/how-to-run-a-local-script-in-remote-server-using-expect-and-bash-script
Also try to disown your process after placing it on the background with disown to keep it from job control. e.g.
whole_command &
disown
Changing its input to /dev/null might also help but it could hang forever if it really needs input from user.
whole_command <&- < /dev/null &
disown

Shell questions

In the following context : VisualVM over ssh
I try to execute the 2 following commands in a single script:
ssh -D 9696 john.doe#121.122.123.124
/usr/bin/jvisualvm -J-Dnetbeans.system_socks_proxy=localhost:9696 \
-J Djava.net.useSystemProxies=true
Having the 2 command like this does not work because the ssh command starts in an interactive mode, so the VisualVM is started after the ssh is closed (explicitly with an 'exit').
What could be a good way to solve that issue?
PS. I am running MacOS X.
try:
ssh john.doe#121.122.123.124 '/usr/bin/jvisualvm -J-Dnetbeans.system_socks_proxy=localhost:9696 -J Djava.net.useSystemProxies=true'
If I understand your use case properly, you want to setup port-forwarding with the ssh connection then the second command is run on the localhost which uses the forwarded port on the localhost. I think you could try the -f or -n options to ssh to achieve this. It does however require a command to be run on the remotehost. You could use a bogus command like echo &> /dev/null for that.
EDIT:
Something like this seemed to work in a naïve test:
ssh -f -D <port> remotehost <dummy_program_that_doesnt_quit>
This is best done using an SSH key and screen, so that we interact with and can close the SSH session.
I'm also presuming jvisualvm takes control of the terminal so that when it exits, we clean up the screen session. If jvisualvm detaches from the terminal, the script immediately jumps to cleaning up the screen session while jvisualvm is running.
ssh-add .ssh/key
screen -dmS sshproxy ssh -i .ssh/key -D 9696 john.doe#121.122.123.124
/usr/bin/jvisualvm -J-Dnetbeans.system_socks_proxy=localhost:9696 \
-J Djava.net.useSystemProxies=true
screen -r -d sshproxy -X quit

Resources