Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,46 @@ $result = Process::ssh([
->run('ls -al');
```

### Use the favorites method provided by Laravel's Process class.

For more information, refer to the official documentation : https://laravel.com/docs/11.x/processes

```php
$process = Process::ssh([
'host' => '192.168.1.10',
'user' => 'username',
'password' => 'your_password',
])
->start('bash import.sh');

$result = $process->wait();

```

```php
[$result1, $result2] = Process::ssh([
'host' => '192.168.1.10',
'user' => 'username',
'password' => 'your_password',
])
->concurrently(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});
```

```php
$result = Process::ssh([
'host' => '192.168.1.10',
'user' => 'username',
'password' => 'your_password',
])
->pool(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});
```

### SSH multiplexing

If you want to execute multiple commands over the same SSH connection, SSH multiplexing allows you to reuse an existing TCP connection, improving efficiency and reducing overhead.
Expand Down
20 changes: 19 additions & 1 deletion src/PendingProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ class PendingProcess extends BasePendingProcess

private bool $handleSsh = false;

/**
* Override the command string to handle SSH commands.
*/
public function command(array|string $command)
{
$command = $this->buildCommand($command);

$this->command = $command;

return $this;
}

/**
* Set configuration for the SSH connection.
*/
Expand Down Expand Up @@ -60,6 +72,10 @@ public function setConfig(array $config, bool $handleSsh)
*/
public function buildCommand(array|string|null $command): array|string|null
{
if (! $command) {
return $command;
}

if (! $this->handleSsh) {
return $command;
}
Expand Down Expand Up @@ -161,6 +177,8 @@ protected function toSymfonyProcess(array|string|null $command)
{
$command = $this->buildCommand($command);

return parent::toSymfonyProcess($command);
$process = parent::toSymfonyProcess($command);

return $process;
}
}
19 changes: 0 additions & 19 deletions src/ProcessSsh.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,6 @@ public function addExtraOption(string $option): self
return $this;
}

public function pool(callable $callback)
{
if ($this->handleSsh) {
throw new \InvalidArgumentException('Cannot pool processes with SSH enabled.');
}

return parent::pool($callback);
}

public function pipe(callable|array $callback, ?callable $output = null)
{
if ($this->handleSsh) {
Expand All @@ -79,16 +70,6 @@ public function pipe(callable|array $callback, ?callable $output = null)
return parent::pipe($callback, $output);
}

public function concurrently(callable $callback, ?callable $output = null)
{

if ($this->handleSsh) {
throw new \InvalidArgumentException('Cannot concurrently processes with SSH enabled.');
}

return parent::concurrently($callback, $output);
}

/**
* Create a new pending process instance.
*/
Expand Down
154 changes: 85 additions & 69 deletions tests/ProcessSshTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
use Bagel\ProcessSsh\PendingProcess;
use Bagel\ProcessSsh\Providers\ProcessSshServiceProvider;
use Illuminate\Process\FakeProcessResult;
use Illuminate\Process\Pool;
use Illuminate\Support\Facades\Process;
use Orchestra\Testbench\TestCase;

uses(TestCase::class)->beforeEach(function () {
$this->app->register(ProcessSshServiceProvider::class);

$this->basicSshConfig = [
'host' => '192.178.0.1',
'user' => 'ubuntu',
'port' => 22,
];
});

it('process config set', function () {
$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'port' => 22,
'extraOptions' => [
Expand All @@ -22,7 +29,7 @@
'private_key' => '/path/to/key',
]);

expect($process->sshConfig()['host'])->toBe('example.com');
expect($process->sshConfig()['host'])->toBe('192.178.0.1');
expect($process->sshConfig()['user'])->toBe('ubuntu');
expect($process->sshConfig()['port'])->toBe(22);
expect($process->sshConfig()['extraOptions'])->toBe([
Expand All @@ -34,7 +41,7 @@

it('process add extra options', function () {
$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'port' => 22,
])->addExtraOption('-o StrictHostKeyChecking=no');
Expand All @@ -46,7 +53,7 @@

it('process disableStrictHostKeyChecking', function () {
$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'port' => 22,
])->disableStrictHostKeyChecking();
Expand Down Expand Up @@ -87,12 +94,12 @@
Process::fake();

$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
])
->disableStrictHostKeyChecking()
->run('ls -al');

expect($process->command())->toBe("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null example.com 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');
expect($process->command())->toBe("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');

Process::assertRan('ls -al');
});
Expand All @@ -101,7 +108,7 @@
Process::fake();

$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
Expand All @@ -113,7 +120,7 @@
->disableStrictHostKeyChecking()
->run('ls -al');

expect($process->command())->toBe("sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@example.com 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');
expect($process->command())->toBe("sshpass -p 'password' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');

Process::assertRan('ls -al');
});
Expand All @@ -122,37 +129,19 @@
Process::fake();

$process = Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'port' => 22,
'private_key' => '/path/to/key',
])
->disableStrictHostKeyChecking()
->run('ls -al');

expect($process->command())->toBe("ssh -i /path/to/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@example.com 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');
expect($process->command())->toBe("ssh -i /path/to/key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');

Process::assertRan('ls -al');
});

it('exception thrown process run with array', function () {
Process::fake();

Process::ssh([
'host' => '127.0.0.1',
])->run(['ls', '-al']);

})->throws(InvalidArgumentException::class, 'Array commands are not supported for SSH connections');

it('exception thrown process start with array', function () {
Process::fake();

Process::ssh([
'host' => '127.0.0.1',
])->start(['ls', '-al']);

})->throws(InvalidArgumentException::class, 'Array commands are not supported for SSH connections');

it('Process can run normaly', function () {
Process::fake();

Expand Down Expand Up @@ -183,7 +172,7 @@
Process::fake();

Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
Expand All @@ -202,7 +191,7 @@
Process::fake();

Process::ssh([
'host' => 'example.com',
'host' => '192.178.0.1',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
Expand All @@ -217,60 +206,87 @@
});
});

it('can\'t pool processes with SSH enabled', function () {
it('invoke process::concurrently', function () {
Process::fake();

Process::ssh([
'host' => 'example.com',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
])->pool(function () {
//
$process = Process::concurrently(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});

})->throws(InvalidArgumentException::class, 'Cannot pool processes with SSH enabled.');
expect($process[0]->command())->toBe('ls -al');
expect($process[1]->command())->toBe('whoami');

Process::assertRan('ls -al');
Process::assertRan('whoami');
});

it('can\'t pipe processes with SSH enabled', function () {
it('invoke process::concurrently ssh', function () {
Process::fake();

Process::ssh([
'host' => 'example.com',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
])->pipe(function () {
//
$process = Process::ssh($this->basicSshConfig)->concurrently(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});

})->throws(InvalidArgumentException::class, 'Cannot pipe processes with SSH enabled.');
expect($process[0]->command())->toBe("ssh ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');
expect($process[1]->command())->toBe("ssh ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'whoami'.PHP_EOL.'EOF-PROCESS-SSH');

});

it('can\'t concurrently processes with SSH enabled', function () {
it('invoke process::pool', function () {
Process::fake();

Process::ssh([
'host' => 'example.com',
'user' => 'ubuntu',
'password' => 'password',
'port' => 22,
])->concurrently(function () {
//
$process = Process::pool(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});

$results = $process->wait();
expect($results[0]->command())->toBe('ls -al');
expect($results[1]->command())->toBe('whoami');

Process::assertRan('ls -al');
Process::assertRan('whoami');
});

it('invoke process::pool ssh', function () {
Process::fake();

$process = Process::ssh($this->basicSshConfig)->pool(function (Pool $pool) {
$pool->command('ls -al');
$pool->command('whoami');
});

})->throws(InvalidArgumentException::class, 'Cannot concurrently processes with SSH enabled.');
$results = $process->wait();
expect($results[0]->command())->toBe("ssh ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'ls -al'.PHP_EOL.'EOF-PROCESS-SSH');
expect($results[1]->command())->toBe("ssh ubuntu@192.178.0.1 'bash -se' << \EOF-PROCESS-SSH".PHP_EOL.'whoami'.PHP_EOL.'EOF-PROCESS-SSH');

});

it('exception thrown process run with array', function () {
Process::fake();

Process::ssh([
'host' => '127.0.0.1',
])->run(['ls', '-al']);

})->throws(InvalidArgumentException::class, 'Array commands are not supported for SSH connections.');

it('exception thrown process start with array', function () {
Process::fake();

// it('timeout process', function () {
// //Process::fake();
Process::ssh([
'host' => '127.0.0.1',
])->start(['ls', '-al']);

// $process = Process::ssh([
// 'host' => '192.168.8.5',
// 'user' => 'ubuntu',
// //'password' => 'password',
// 'port' => 22,
// ])
// ->run('ls');
})->throws(InvalidArgumentException::class, 'Array commands are not supported for SSH connections.');

// dump($process->errorOutput());
// dump($process->output());
it('invoke process::pipe', function () {
Process::fake();

// })->only();
$process = Process::ssh($this->basicSshConfig)->pipe([
'ls -al',
'whoami',
]);
})->throws(InvalidArgumentException::class, 'Cannot pipe processes with SSH enabled.');
Loading