Host SSH Options

This commit is contained in:
Michael Woodward 2017-04-12 19:07:59 +01:00
parent 542e5f0dc2
commit 54b683c556
3 changed files with 114 additions and 41 deletions

View File

@ -9,6 +9,7 @@ namespace Deployer\Host;
use Deployer\Configuration\Configuration; use Deployer\Configuration\Configuration;
use Deployer\Configuration\ConfigurationAccessor; use Deployer\Configuration\ConfigurationAccessor;
use Deployer\Ssh\Options;
class Host class Host
{ {
@ -21,7 +22,7 @@ class Host
private $identityFile; private $identityFile;
private $forwardAgent = true; private $forwardAgent = true;
private $multiplexing = null; private $multiplexing = null;
private $options = []; private $options;
/** /**
* @param string $hostname * @param string $hostname
@ -30,35 +31,27 @@ class Host
{ {
$this->hostname = $hostname; $this->hostname = $hostname;
$this->config = new Configuration(); $this->config = new Configuration();
$this->options = $this->initOptions();
} }
/** private function initOptions() : Options
* Generate options string for ssh
*
* @return string
*/
public function sshOptions()
{ {
$options = ''; $options = new Options;
if ($this->port) { if ($this->port) {
$options .= " -p {$this->port}"; $options = $options->withOption('-p', $this->port);
} }
if ($this->configFile) { if ($this->configFile) {
$options .= " -F {$this->configFile}"; $options = $options->withOption('-F', $this->configFile);
} }
if ($this->identityFile) { if ($this->identityFile) {
$options .= " -i {$this->identityFile}"; $options = $options->withOption('-i', $this->identityFile);
} }
if ($this->forwardAgent) { if ($this->forwardAgent) {
$options .= " -A"; $options = $options->withFlag('-A');
}
foreach ($this->options as $option) {
$options .= " -o $option";
} }
return $options; return $options;
@ -202,31 +195,32 @@ class Host
return $this; return $this;
} }
/** public function getOptions() : Options
* @return array
*/
public function getOptions()
{ {
return $this->options; return $this->options;
} }
/** public function options(array $options) : Host
* @param array $options
* @return $this
*/
public function options(array $options)
{ {
$this->options = $options; $this->options = $this->options->withOptions($options);
return $this; return $this;
} }
/** public function flags(array $flags) : Host
* @param string $option
* @return $this
*/
public function addOption(string $option)
{ {
$this->options[] = $option; $this->options = $this->options->withFlags($flags);
return $this;
}
public function addOption(string $option, $value) : Host
{
$this->options = $this->options->withOption($option, $value);
return $this;
}
public function addFlag(string $flag) : Host
{
$this->options = $this->options->withFlag($flag);
return $this; return $this;
} }

View File

@ -56,17 +56,17 @@ class Client
$this->pop->command($hostname, $command); $this->pop->command($hostname, $command);
$options = $host->sshOptions(); $options = $host->getOptions();
$become = $host->has('become') ? 'sudo -u ' . $host->get('become') : ''; $become = $host->has('become') ? 'sudo -u ' . $host->get('become') : '';
// When tty need to be allocated, don't use multiplexing, // When tty need to be allocated, don't use multiplexing,
// and pass command without bash allocation on remote host. // and pass command without bash allocation on remote host.
if ($config['tty']) { if ($config['tty']) {
$this->output->write(''); // Notify OutputWatcher $this->output->write(''); // Notify OutputWatcher
$options .= ' -tt'; $options = $options->withFlag('-tt');
$command = escapeshellarg($command); $command = escapeshellarg($command);
$ssh = "ssh $options $host $command"; $ssh = "ssh {$options->getOptionsString()} $host $command";
$process = new Process($ssh); $process = new Process($ssh);
$process $process
->setTimeout($config['timeout']) ->setTimeout($config['timeout'])
@ -80,7 +80,7 @@ class Client
$options = $this->initMultiplexing($host); $options = $this->initMultiplexing($host);
} }
$ssh = "ssh $options $host $become 'bash -s; printf \"[exit_code:%s]\" $?;'"; $ssh = "ssh {$options->getOptionsString()} $host $become 'bash -s; printf \"[exit_code:%s]\" $?;'";
$process = new Process($ssh); $process = new Process($ssh);
$process $process
@ -126,14 +126,18 @@ class Client
*/ */
private function initMultiplexing(Host $host) private function initMultiplexing(Host $host)
{ {
$options = $host->sshOptions(); $options = $host->getOptions();
$controlPath = $this->generateControlPath($host); $controlPath = $this->generateControlPath($host);
$options .= " -o ControlMaster=auto"; $multiplexDefaults = (new Options)->withOptions([
$options .= " -o ControlPersist=60"; '-o ControlMaster' => 'auto',
$options .= " -o ControlPath=$controlPath"; '-o ControlPersist' => '60',
'-o ControlPath' => $controlPath,
]);
$process = new Process("ssh $options -O check -S $controlPath $host 2>&1"); $options = $options->withDefaults($multiplexDefaults);
$process = new Process("ssh {$options->getOptionsString()} -O check -S $controlPath $host 2>&1");
$process->run(); $process->run();
if (!preg_match('/Master running/', $process->getOutput()) && $this->output->isVeryVerbose()) { if (!preg_match('/Master running/', $process->getOutput()) && $this->output->isVeryVerbose()) {

75
src/Ssh/Options.php Normal file
View File

@ -0,0 +1,75 @@
<?php
namespace Deployer\Ssh;
/**
* @author Michael Woodward <mikeymike.mw@gmail.com>
*/
class Options
{
/**
* @var array
*/
private $flags = [];
/**
* @var array
*/
private $options = [];
public function getOptionsString() : string
{
$flags = implode(' ', $this->flags);
$options = implode(' ', array_map(function ($key, $value) {
return sprintf('%s=%s', $key, $value);
}, array_keys($this->options), $this->options));
return sprintf('%s %s', $flags, $options);
}
public function withFlags(array $flags) : Options
{
$clone = clone $this;
$clone->flags = $flags;
return $clone;
}
public function withOptions(array $options) : Options
{
$clone = clone $this;
$clone->options = $options;
return $clone;
}
public function withFlag($flag) : Options
{
$clone = clone $this;
$clone->flags = array_unique(array_merge($this->flags, [$flag]));
return $clone;
}
public function withOption(string $option, string $value) : Options
{
$clone = clone $this;
$clone->options = array_merge($this->options, [$option => $value]);
return $clone;
}
public function withDefaults(Options $defaultOptions) : Options
{
$clone = clone $this;
$clone->flags = array_merge($defaultOptions->flags, $this->flags);
$clone->options = array_merge($defaultOptions->options, $this->options);
return $clone;
}
public function __toString() : string
{
return $this->getOptionsString();
}
}