Deployer: `dep ssh` does not work with fish shell on remote system

Created on 26 Sep 2017  ·  14Comments  ·  Source: deployphp/deployer

| Q | A
| ----------------- | ---
| Issue Type | Bug (or feature request?)
| Deployer Version | 6.0.3
| Local Machine OS | archlinux 2017-09
| Remote Machine OS | debian stretch

Description

dep ssh does not work with fish shell on the remote system:

hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> dep ssh
Select host:
  [blog.xxxxxxxxx.dev] [email protected]
  [blog.xxxxxxxxx    ] [email protected]
 > blog.xxxxxxxxx.dev
The authenticity of host 'blog.xxxxxxxxx.dev (192.168.150.59)' can't be established.
ECDSA key fingerprint is SHA256:+PjtDcpz+TZrYb9XcLMMVRE4uovxFYgsUBVMVsuPCiU.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'blog.xxxxxxxxx.dev,192.168.150.59' (ECDSA) to the list of known hosts.
cd: The directory “/containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current” does not exist
/usr/share/fish/functions/cd.fish (line 30):     builtin cd $argv
                                                 ^
in function “cd”
        called on standard input
        with parameter list “/containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current”

Variables may not be used as commands. In fish, please define a function or use 'eval $SHELL'.
fish: cd /containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current; exec $SHELL -l
                                                                                  ^
Connection to blog.xxxxxxxxx.dev closed.

Steps to reproduce

  1. setup account with fish shell on the remote system: chsh -s /usr/bin/fish
  2. setup deploy.php which points to that host
  3. connect with dep ssh

Content of deploy.php

<?php

namespace Deployer;

require 'recipe/common.php';

define('CONTAINER', 'blog-xxxxxxxxx');
define('DOMAIN', 'blog.xxxxxxxxx');

host(sprintf('%s.dev', DOMAIN))
    ->stage('vagrant')
    ->user(CONTAINER)
    ->set('deploy_path', sprintf('/containers/%s/domains/%s/deployer', CONTAINER, DOMAIN));

Output log

With enabled option for verbose output -vvv.

hiciu@unknown ~/s/2/2/temp> dep -vvv ssh
cd: The directory “/containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current” does not exist
/usr/share/fish/functions/cd.fish (line 30):     builtin cd $argv
                                                 ^
in function “cd”
        called on standard input
        with parameter list “/containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current”
Variables may not be used as commands. In fish, please define a function or use 'eval $SHELL'.
fish: cd /containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/current; exec $SHELL -l
                                                                                  ^
Connection to blog.xxxxxxxxx.dev closed.

Comments

For the simple tasks deployer works just fine with fish.

The offending line is here: https://github.com/deployphp/deployer/blob/master/src/Console/SshCommand.php#L87

Most helpful comment

Hello,

I have new patch for 6.2.0. It seems to be working fine on my system.

diff --git a/src/Ssh/Client.php b/src/Ssh/Client.php
index 04392b7..ee27ba0 100644
--- a/src/Ssh/Client.php
+++ b/src/Ssh/Client.php
@@ -66,6 +66,7 @@ class Client
             $this->output->write(''); // Notify OutputWatcher
             $sshArguments = $sshArguments->withFlag('-tt');
             $command = escapeshellarg($command);
+            $command = escapeshellarg("bash -c $command");

             $ssh = "ssh $sshArguments $host $command";
             $process = new Process($ssh);
@@ -83,7 +84,7 @@ class Client

         $shellCommand = $host->getShellCommand();

-        $ssh = "ssh $sshArguments $host $become '$shellCommand; printf \"[exit_code:%s]\" $?;'";
+        $ssh = "ssh $sshArguments $host $become bash -c \"'$shellCommand; printf \"[exit_code:%s]\" $?;'\"";

         $process = new Process($ssh);
         $process

All 14 comments

Correct, try to run this commands in terminal:

ssh $host 'echo $0'
hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> ssh [email protected] 'echo $0'

hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> ssh [email protected] 'echo $SHELL'
/usr/bin/fish
hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> ssh [email protected] 'exec $SHELL'
Variables may not be used as commands. In fish, please define a function or use 'eval $SHELL'.
fish: exec $SHELL
           ^

It seems that eval $SHELL works in bash and in fish:

bash test:

hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> ssh -t [email protected] 'eval $SHELL -l'
blog-xxxxxxxxx@blog-xxxxxxxxx:/containers/blog-xxxxxxxxx$ ls
blog  conf  domains  logs  README.md  secrets.json
blog-xxxxxxxxx@blog-xxxxxxxxx:/containers/blog-xxxxxxxxx$ logout
Connection to blog.xxxxxxxxx.dev closed.

fish test:

hiciu@unknown ~/d/k/d/s/blog (feature/deployer)> ssh -t [email protected] 'eval $SHELL -l'
blog-xxxxxxxxx@blog-xxxxxxxxx ~> ls
blog/  conf/  domains/  logs/  README.md  secrets.json
blog-xxxxxxxxx@blog-xxxxxxxxx ~>

Connection to blog.xxxxxxxxx.dev closed.

Although on the process list I'll see two processes; parent process fish -c eval $SHELL -l and child /usr/bin/fish -l. There are old tickets in the fish project ([1], [2]) that are suggesting eval exec $SHELL -l as a solution. This too works with both bash and fish and it does not create additional processes.

[1] https://github.com/fish-shell/fish-shell/issues/708
[2] https://github.com/fish-shell/fish-shell/issues/154

Can you create a server where i can test it?

Please try these:

ssh [email protected]
ssh [email protected]
ssh [email protected]

I've added your keys from https://github.com/antonmedv.keys.

Ok! Thanks. Will test it tomorrow.

after patching that on my local version dep deploy fails with:

  [Deployer\Exception\RuntimeException]
  The command "rm -f /containers/blog-xxxxxxxxx/domains/blog.xxxxxxxxx/deployer/.dep/deploy.lock" failed.
  Exit Code: -1 (Unknown error)
  Host Name: blog.xxxxxxxxx
  ================
  $? is not the exit status. In fish, please use $status.
  fish: bash -s; printf "[exit_code:%s]" $?;

I think deployer should explicitly call bash. This patch allows me to deploy stuff with fish on the remote system:

diff --git a/src/Ssh/Client.php b/src/Ssh/Client.php
index 250b8c0..621fb5b 100644
--- a/src/Ssh/Client.php
+++ b/src/Ssh/Client.php
@@ -80,7 +80,7 @@ class Client
             $sshArguments = $this->initMultiplexing($host);
         }

-        $ssh = "ssh $sshArguments $host $become 'bash -s; printf \"[exit_code:%s]\" $?;'";
+        $ssh = "ssh $sshArguments $host $become bash -c \"'bash -s; printf \"[exit_code:%s]\" $?;'\"";

         $process = new Process($ssh);
         $process

Nice! Will ad it to hew release. Thanks for finding a bug!

Ok! Thanks. Will test it tomorrow.

How did that testing went? Should I destroy ec2-18-194-81-174 instance?

Hello,

I have new patch for 6.2.0. It seems to be working fine on my system.

diff --git a/src/Ssh/Client.php b/src/Ssh/Client.php
index 04392b7..ee27ba0 100644
--- a/src/Ssh/Client.php
+++ b/src/Ssh/Client.php
@@ -66,6 +66,7 @@ class Client
             $this->output->write(''); // Notify OutputWatcher
             $sshArguments = $sshArguments->withFlag('-tt');
             $command = escapeshellarg($command);
+            $command = escapeshellarg("bash -c $command");

             $ssh = "ssh $sshArguments $host $command";
             $process = new Process($ssh);
@@ -83,7 +84,7 @@ class Client

         $shellCommand = $host->getShellCommand();

-        $ssh = "ssh $sshArguments $host $become '$shellCommand; printf \"[exit_code:%s]\" $?;'";
+        $ssh = "ssh $sshArguments $host $become bash -c \"'$shellCommand; printf \"[exit_code:%s]\" $?;'\"";

         $process = new Process($ssh);
         $process

The above patch also fixes running deployment on windows (using plink.exe renamed to ssh.exe...so one can use pageant).

BR

Solved as well an error that exit_code was never properly returned by the remote. In Client::parseExitStatus:

$output = $process->getOutput();
var_dump($output);

Without:

# For an echo 123 on the remote
string(4) "123
"

-> that would raise an exception quickly after that

With patch:

# For an echo 123 on the remote
string(17) "123
[exit_code:0]"

Any progress on this?

It should work now.

Unfortunately I can't confirm.

hiciu@unknown ~/s/2/2/l/k/2/scripts (master)> php deployer.phar --version
Deployer 6.4.6
hiciu@unknown ~/s/2/2/l/k/2/scripts (master)> php deployer.phar deploy
✈ Deploying master on xxx
✈ Deploying master on yyy
✈ Deploying master on zzz
➤ Executing task deploy:prepare
✔ Executing task deploy:failed
➤ Executing task deploy:unlock

In Client.php line 103:

  The command "rm -f ~/api//.dep/deploy.lock" failed.      

  Exit Code: -1 (Unknown error)                            

  Host Name: xxx                                  

  ================                                         
  $? is not the exit status. In fish, please use $status.  
  fish: bash -s; printf "[exit_code:%s]" $?;               
                                          ^                


deploy [-p|--parallel] [-l|--limit LIMIT] [--no-hooks] [--log LOG] [--roles ROLES] [--hosts HOSTS] [-o|--option OPTION] [--] [<stage>]
Was this page helpful?
0 / 5 - 0 ratings

Related issues

dima-stefantsov picture dima-stefantsov  ·  4Comments

sweebee picture sweebee  ·  3Comments

flashios09 picture flashios09  ·  4Comments

timkley picture timkley  ·  4Comments

brunodevel picture brunodevel  ·  3Comments