Laravel SSH - create tmux session - laravel

I have the following:
\Config::set('remote.connections.runtime.host', $server->server_ip);
$commands = [
'tmux'
];
\SSH::run($commands, function($line) {
echo $line.PHP_EOL;
});
dd();
This outputs the following error:
open terminal failed: not a terminal
Is it possible to create a tmux session this way?

There's nothing you can do to make this work with Laravel SSH. However, Laravel's SSH component uses phpseclib SSH internally which is more flexible when used directly.
Now I'm assuming you're trying to create a tmux session to start some process that you want to continue running in the background after the SSH connection has ended. The good part is that since phpseclib is a dependency of Laravel SSH it's already there so there's no need to install it. I'm not very familiar with tmux and it's options, but I can offer a solution that uses screen instead:
use \phpseclib\Net\SSH2;
use \phpseclib\File\ANSI;
$ssh = new SSH2('host');
$ansi = new ANSI();
if ($ssh->login('username', 'password')) {
// The command below will start a screen
// session and automatically detach it
$ssh->write("screen -m -d -S processes top\n");
// You can include the lines below to see the
// output of the write command converted to HTML
$ansi->appendString($ssh->read());
echo $ansi->getScreen();
}
This creates a new automatically detached screen session named processes and runs the top command in it. To connect to the session you can simply run this in your console:
ssh username#host -t "screen -r processes"
This will reattach the processes session so you can see what's going on. Of course you could adapt this to use tmux if that's you're preference.

Related

tmux: attach to existing session in new grouped session

I want to start tmux when opening a new terminal window via shortcut (ALT+F1).
tmux should start a new session when there is no session that I can attach to.
If there is an existing session, but I am not attached to it, simply attach.
If there is an existing session and I am already attached to it (i.e., I am opening a 2nd terminal window), I want to attach to the same session and be able to work on another window.
Currently, I am using the following script called tmux-init for the first two points:
#!/bin/sh
# Attach TMUX, or else open new session
if [[ -x "$(command -v tmux)" ]] && [[ -n "${DISPLAY}" ]] && [[ -z "${TMUX}" ]]; then
tmux attach || tmux >/dev/null 2>&1
fi
This automatically attaches to my existing session, or creates a new one when it does not exist.
However, I want to be able to open multiple windows and work on all of them at the same time.
Currently, all of the opened windows would be attached to the same session and mirror everything. The idea was to use tmux groups (tmux new-session -t 0), but my knowledge of bash scripting and tmux is limited. Here is what I currently have (tmux-init-2):
#!/bin/sh
tmuxtest=$(tmux ls | grep attached | grep "group 0")
if [[ ! -z "$tmuxtest" ]]
then
tmux new-session -t 0
tmux set-option destroy-unattached on
tmux new-window
else
tmux-init
fi
This works sometimes, sometimes it does not open a new window, sometimes it does not destroy the grouped session on detach... I can't seem to find a pattern. In most cases, the new window opens after I detach from the session. It seems that I should pass the options to tmux in a different way - but I have not found a way to create a new session and set options for that session immediately. Is there a better way to do it?

Leaving a Command Running on a Remote Server

Forgive me if this is something I've just completely missed, however, I have a remote server (a NAS) that I'd like to start a command running on, while I do some work locally. Now, I believe I could probably do this with a command like:
ssh foo#bar 'cp -Rl /foo/bar /bar/foo'
However, I need a return value in my main script from part of the command, so I need it to return but leave the cp command running. For example:
foo=$(ssh foo#bar <<- REMOTE_COMMANDS
cp -Rl /foo/bar /bar/foo &
echo "foobar"
REMOTE_COMMANDS)
However I don't believe this returns until the cp command has completed, but if I use exit I think the cp is interrupted?
Is there another way to leave cp running, or will I need to run two ssh commands (one for the cp, one to get the return value I need?)
You can use one the following choices :
tmux
nohup
screen
tmux & screen are some complete environments that can be attached and detached for 1 to N users.
If you need something straightforward, look nohup first.
You can use screen command.
Simply create a new screen using : screen -R screen_name.
Run your command or code and then exit that screen by pressing ctrl + a + d.
If you want to switch back to the screen, enter this command : screen -r screen_name.
Hope it helps.

how to script commands that will be executed on a device connected via ssh?

So, I've established a connection via ssh to a remote machine; and now what I would like to do is to execute few commands, grab some files and copy them back to my host machine.
I am aware that I can run
ssh user#host "command1; command2;....command_n"
and then close the connection, but how can I do the same without use the aforememtioned syntax? I have a lot of complex commands that has a bunch of quote and characters that would be a mess to escape.
Thanks!
My immediate thought is why not create a script and push it over to the remote machine to have it run locally in a text file? If you can't for whatever reason, I fiddled around with this and I think you could probably do well with a HEREDOC:
ssh -t jane#stackoverflow.com bash << 'EOF'
command 1 ...
command 2 ...
command 3 ...
EOF
and it seems to do the right thing. Play with your heredoc to keep your quotes safe, but it will get tricky. The only other thing I can offer (and I totally don't recomend this) is you could use a toy like perl to read and write to the ssh process like so:
open S, "| ssh -i ~/.ssh/host_dsa -t jane#stackoverflow.com bash";
print S "date\n"; # and so on
but this is a really crummy way to go about things. Note that you can do this in other languages.
Instead of the shell use some scripting language (Perl, Python, Ruby, etc.) and some module that takes care of the ugly work. For example:
#!/usr/bin/perl
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host, user => $user);
$ssh->system('echo', 'Net::Open$$H', 'Quot%$', 'Th|s', '>For', 'You!');
$ssh->system({stdout_file => '/tmp/ls.out'}, 'ls');
$ssh->scp_put($local_path, $remote_path);
my $out = $ssh->capture("find /etc");
From here: Can I ssh somewhere, run some commands, and then leave myself a prompt?
The use of an expect script seems pretty straightforward... Copied from the above link for convenience, not mine, but I found it very useful.
#!/usr/bin/expect -f
spawn ssh $argv
send "export V=hello\n"
send "export W=world\n"
send "echo \$V \$W\n"
interact
I'm guessing a line like
send "scp -Cpvr someLocalFileOrDirectory you#10.10.10.10/home/you
would get you your files back...
and then:
send "exit"
would terminate the session - or you could end with interact and type in the exit yourself..

Can Cron Jobs Use Gnome-Open?

I am running Ubuntu 11.10 (Unity interface) and I created a Bash script that uses 'gnome-open' to open a series of web pages I use every morning. When I manually execute the script in the Terminal, the bash script works just fine. Here's a sample of the script (it's all the same so I've shortened it):
#!/bin/bash
gnome-open 'https://docs.google.com';
gnome-open 'https://mail.google.com';
Since it seemed to be working well, I added a job to my crontab (mine, not root's) to execute every weekday at a specific time.
Here's the crontab entry:
30 10 * * 1,2,3,4,5 ~/bin/webcheck.sh
The problem is this error gets returned for every single 'gnome-open' command in the bash script:
GConf-WARNING **: Client failed to connect to the D-BUS daemon:
Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
GConf Error: No D-BUS daemon running
Error: no display specified
I did some searching to try and figure this out. The first thing I tried was relaunching the daemon using SIGHUP:
killall -s SIGHUP gconfd-2
That didn't work so I tried launching the dbus-daemon using this code from the manpage for dbus-launch:
## test for an existing bus daemon, just to be safe
if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
## if not found, launch a new one
eval `dbus-launch --sh-syntax --exit-with-session`
echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
fi
But that didn't do anything.
I tried adding simply 'dbus-launch' at the top of my bash script and that didn't work either.
I also tried editing the crontab to include the path to Bash, because I saw that suggestion on another thread but that didn't work.
Any ideas on how I can get this up and running?
Here is how the problem was solved. It turns out the issue was primarily caused by Bash not having access to an X window session (or at least that's how I understood it). So my problem was solved by editing my crontab like so:
30 10 * * 1,2,3,4,5 export DISPLAY=:0 && ~/bin/webcheck.sh
The "export DISPLAY=:0" statement told cron which display to use. I found the answer on this archived Ubuntu forum after searching for "no display specified" or something like that:
http://ubuntuforums.org/archive/index.php/t-105250.html
So now, whenever I'm logged in, exactly at 10:30 my system will automatically launch a series of webpages that I need to look at every day. Saves me having to go through the arduous process of typing in my three-letter alias every time :)
Glad you asked!
It depends on when it is run.
If the Gnome GDM Greeter is live, you can use the DBUS session from the logon dialog, if you will. You can, e.g., use this to send notifications to the logon screen, if no-one is logged in:
function do_notification
{
for pid in $(pgrep gnome-session); do
unset COOKIE
COOKIE="$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$pid/environ|cut -d= -f2-)"
GNUSER="$(ps --no-heading -o uname $pid)"
echo "Notifying user $GNUSER (gnome-session $pid) with '$#'"
sudo -u "$GNUSER" DBUS_SESSION_BUS_ADDRESS="$COOKIE" /usr/bin/notify-send -c "From CRON:" "$#"
done
unset COOKIE
}
As you can see the above code simply runs the same command (notify-send) on all available gnome-sessions, when called like:
do_notification "I wanted to let you guys know"
You can probably pick this apart and put it to use for your own purposes.

How can one specify a user's emacs init file to load with emacsclient?

Question
How can one specify a user's emacs init file to load with emacsclient?
emacsclient does not understand '-u user' and '-a ALTERNATE-EDITOR' does not allow me to quote it and provide '-u user'.
For example, running:
/usr/bin/emacsclient -n -a '/usr/bin/emacs -u <username>' ~<username>/notes.txt
returns
/usr/bin/emacsclient: error executing alternate editor "/usr/bin/emacs -u <username>"
Background
I'm using emacs version 23.1.1 and emacsclient version 23.1.
emacs itself supports '-u user' to load a specified user's init file.
I use the following bash function in my aliases file to invoke emacs
# a wrapper is needed to sandwich multiple command line arguments in bash
# 2>/dev/null hides
# "emacsclient: can't find socket; have you started the server?"
emacs_wrapper () {
if [ 0 -eq $# ]
then
/usr/bin/emacsclient -n -a /usr/bin/emacs ~<username>/notes.txt 2>/dev/null &
else
/usr/bin/emacsclient -n -a /usr/bin/emacs $* 2>/dev/null &
fi
}
alias x='emacs_wrapper'
Typing x followed by a list of files:
Connects to an existing emacs server if one is running, otherwise starts a new one
Executes as a background process
Opens the list of files or my notes file if no files are provided
This works great when I'm logged in as myself. However, many production boxes require me to log in as a production user. I've separated my aliases into a bash script, therefore I can get my aliases and bash functions by simply running.
. ~<username>/alias.sh
Unfortunately, this won't let me use my .emacs file (~<username>/.emacs) :(
This problem has been driving me crazy.
If you can't include command line arguments in your alternate editor specification, then simply write a shell script which does that for you, and supply that as the alternate editor argument instead.
#!/bin/sh
emacs -u (username) "$#"
The point of the server/client model is that you have an existing Emacs with its own set of configurations, and then you connect via one or more clients.
What should the client do if the server was already configured to show the menu bar (a global setting), and the client says not to show it? What if another client attaches saying to show it?
If you want to use different settings for Emacs, use different emacs sessions.

Resources