Skip to content

Commit

Permalink
Merge pull request #60 from mitchdav/feature/database-tunnel-command
Browse files Browse the repository at this point in the history
Add database:tunnel command
  • Loading branch information
taylorotwell authored Jul 15, 2020
2 parents 2a784af + 3e1369a commit ca01415
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
100 changes: 100 additions & 0 deletions src/Commands/DatabaseTunnelCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

namespace Laravel\VaporCli\Commands;

use Laravel\VaporCli\Helpers;
use Symfony\Component\Console\Input\InputArgument;

class DatabaseTunnelCommand extends Command
{
/**
* Configure the command options.
*
* @return void
*/
protected function configure()
{
$this
->setName('database:tunnel')
->addArgument('database', InputArgument::REQUIRED, 'The name of the database')
->addArgument('port', InputArgument::OPTIONAL, 'The local port to serve connections on')
->setDescription('Create a secure tunnel to a database, allowing local connections');
}

/**
* Execute the command.
*
* @return void
*/
public function handle()
{
Helpers::ensure_api_token_is_available();

$databases = $this->vapor->databases();

if (! is_numeric($databaseId = $this->argument('database'))) {
$databaseId = $this->findIdByName($databases, $databaseId);
}

if (is_null($databaseId)) {
Helpers::abort('Unable to find a database with that name / ID.');
}

$jumpBox = $this->findCompatibleJumpBox(
$database = collect($databases)->firstWhere('id', $databaseId)
);

$localPort = $this->argument('port') ?? ($database['port'] - 1);

Helpers::line('<info>Establishing secure tunnel to</info> <comment>['.$database['name'].']</comment> <info>on</info> <comment>[localhost:'.$localPort.']</comment><info>...</info>');

passthru(sprintf('ssh ec2-user@%s -i %s -o LogLevel=error -L %d:%s:%d -N',
$jumpBox['endpoint'],
$this->storeJumpBoxKey($jumpBox),
$localPort,
$database['endpoint'],
$database['port']
));
}

/**
* Find a jump-box compatible with the database.
*
* @param array $database
* @return array
*/
protected function findCompatibleJumpBox(array $database)
{
$jumpBoxes = collect($this->vapor->jumpBoxes())->filter(function ($jumpBox) use ($database) {
return $jumpBox['network_id'] == $database['network_id'];
});

$jumpBox = in_array($database['type'], ['rds', 'aurora-serverless'])
? $jumpBoxes->first()
: $jumpBoxes->firstWhere('version', '>', 1);

if (is_null($jumpBox)) {
Helpers::abort('A compatible jumpbox is required in order to create a tunnel.');
}

return $jumpBox;
}

/**
* Store the private SSH key for the jump-box.
*
* @param array $jumpBox
* @return string
*/
protected function storeJumpBoxKey(array $jumpBox)
{
file_put_contents(
$path = Helpers::home().'/.ssh/vapor-database-shell',
$this->vapor->jumpBoxKey($jumpBox['id'])['private_key']
);

chmod($path, 0600);

return $path;
}
}
1 change: 1 addition & 0 deletions vapor
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ $app->add(new Commands\DatabaseUsersCommand);
$app->add(new Commands\DatabaseUserCommand);
$app->add(new Commands\DatabaseDropUserCommand);
$app->add(new Commands\DatabaseShellCommand);
$app->add(new Commands\DatabaseTunnelCommand);
$app->add(new Commands\DatabaseDeleteCommand);

// Caches...
Expand Down

0 comments on commit ca01415

Please sign in to comment.