Skip to content

Commit 4c1e9d9

Browse files
committed
#12 : Add proxy command for port forwarding
1 parent f1db046 commit 4c1e9d9

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

Diff for: bin/kloud

+5
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ $app->addCommands([
128128
Command\Environment\ShellCommand::$defaultName,
129129
$app,
130130
)),
131+
132+
(new Command\Environment\ProxyCommand(
133+
Command\Environment\ProxyCommand::$defaultName,
134+
$app,
135+
)),
131136
]);
132137

133138
$app->run(new ArgvInput($argv), new ConsoleOutput());
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Cloud\Platform\Console\Command\Environment;
6+
7+
use Deployer\Host\Host;
8+
use Kiboko\Cloud\Domain\Environment\DTO\Context;
9+
use Kiboko\Cloud\Platform\Console\EnvironmentWizard;
10+
use Symfony\Component\Console\Application as Console;
11+
use Symfony\Component\Console\Command\Command;
12+
use Symfony\Component\Console\Input\InputInterface;
13+
use Symfony\Component\Console\Output\OutputInterface;
14+
use Symfony\Component\Console\Question\ChoiceQuestion;
15+
use Symfony\Component\Console\Question\Question;
16+
use Symfony\Component\Console\Style\SymfonyStyle;
17+
use Symfony\Component\Finder\Finder;
18+
use Symfony\Component\Finder\SplFileInfo;
19+
use Symfony\Component\Process\Process;
20+
use Symfony\Component\Serializer\Encoder\YamlEncoder;
21+
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
22+
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
23+
use Symfony\Component\Serializer\Serializer;
24+
25+
final class ProxyCommand extends Command
26+
{
27+
public static $defaultName = 'environment:proxy';
28+
private Console $console;
29+
private EnvironmentWizard $wizard;
30+
31+
public function __construct(?string $name, Console $console)
32+
{
33+
$this->console = $console;
34+
$this->wizard = new EnvironmentWizard();
35+
parent::__construct($name);
36+
}
37+
38+
protected function configure()
39+
{
40+
$this->setDescription('Port forwarding using ssh tunnel');
41+
42+
$this->wizard->configureConsoleCommand($this);
43+
}
44+
45+
protected function execute(InputInterface $input, OutputInterface $output)
46+
{
47+
$workingDirectory = $input->getOption('working-directory') ?: getcwd();
48+
49+
$finder = (new Finder())
50+
->files()
51+
->ignoreDotFiles(false)
52+
->in($workingDirectory);
53+
54+
$format = new SymfonyStyle($input, $output);
55+
56+
$serializer = new Serializer(
57+
[
58+
new CustomNormalizer(),
59+
new PropertyNormalizer(),
60+
],
61+
[
62+
new YamlEncoder(),
63+
]
64+
);
65+
66+
if ($finder->hasResults()) {
67+
/** @var SplFileInfo $file */
68+
foreach ($finder->name('/^\.?kloud.environment.ya?ml$/') as $file) {
69+
try {
70+
/** @var Context $context */
71+
$context = $serializer->deserialize($file->getContents(), Context::class, 'yaml');
72+
} catch (\Throwable $exception) {
73+
$format->error($exception->getMessage());
74+
continue;
75+
}
76+
77+
break;
78+
}
79+
}
80+
81+
if (!isset($context)) {
82+
$format->error('No .kloud.environment.yaml file found in your directory. You must initialize it using environment:init command');
83+
84+
return 1;
85+
}
86+
87+
$host = new Host($context->deployment->server->hostname);
88+
$host->port($context->deployment->server->port);
89+
$host->user($context->deployment->server->username);
90+
91+
$type = $format->askQuestion(new ChoiceQuestion('What type of port forwarding is it?', ['Local to remote', 'Remote to local']));
92+
$localPort = $format->askQuestion(new Question('What is the local port you want to tunnel?'));
93+
$remotePort = $format->askQuestion(new Question('What is the remote port you want to tunnel?'));
94+
95+
if ('Local' === $type) {
96+
$process = new Process(['ssh', '-L', $localPort.':'.$host->getHostname().':'.$remotePort, $host->getUser().'@'.$host->getHostname()]);
97+
} else {
98+
$process = new Process(['ssh', '-R', $remotePort.':127.0.0.1:'.$localPort, $host->getUser().'@'.$host->getHostname()]);
99+
}
100+
101+
try {
102+
$process->setTty(Process::isTtySupported())->setTimeout(0)->mustRun();
103+
} catch (\Exception $exception) {
104+
$format->error($exception->getMessage());
105+
106+
return 1;
107+
}
108+
109+
return 0;
110+
}
111+
}

0 commit comments

Comments
 (0)