Moving things forward

This commit is contained in:
James Gilliland 2022-03-10 19:56:41 -06:00
parent 0083bddfca
commit 0569b34086
9 changed files with 293 additions and 88 deletions

View file

@ -40,12 +40,13 @@ final class GenDuid extends Command
$manufacturer = '001E46'; $manufacturer = '001E46';
} }
$question = new Question('Serial number?'); $question = new Question('Serial number: ');
/** @var string $serial */ /** @var string $serial */
$serial = $helper->ask($input, $output, $question); $serial = $helper->ask($input, $output, $question);
$output->writeln('Identifier: ' . $this->ascii2hex($manufacturer . ':' . $serial)); $id = $this->ascii2hex($manufacturer . ':' . $serial);
$output->write($this->getInstructions()); $output->writeln('Identifier: ' . $id);
$output->write($this->getInstructions($id));
return Command::SUCCESS; return Command::SUCCESS;
} }
@ -60,7 +61,7 @@ final class GenDuid extends Command
return implode(':', $bytes); return implode(':', $bytes);
} }
private function getInstructions(): string private function getInstructions($id): string
{ {
return <<<EOF return <<<EOF
@ -70,7 +71,7 @@ IPv6 Options
DHCP6 DUID: DUID-EN DHCP6 DUID: DUID-EN
DUID-EN DUID-EN
Enterprise Number: 3561 Enterprise Number: 3561
Identifier: As shown above Identifier: $id
Click Save. Click Save.
@ -82,7 +83,7 @@ General Configuration
Other options are probably needed, so set those too. Other options are probably needed, so set those too.
Click Save. This will finally save dhcp6c's DUID file and start the client. Click Save. This will finally save DHCP6's DUID file and start the client.
Step 4) Finished, hopefully. Step 4) Finished, hopefully.

View file

@ -5,7 +5,8 @@ declare(strict_types=1);
namespace Pfatt\Commands; namespace Pfatt\Commands;
use Pfatt\Service\Config; use Pfatt\Service\Config;
use Pfatt\Service\NgController; use Pfatt\Service\IfConfig;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -18,17 +19,20 @@ final class Monitor extends Command
protected static $defaultDescription = 'Monitor connection to trigger 5268AC updates'; protected static $defaultDescription = 'Monitor connection to trigger 5268AC updates';
protected Config $config; protected Config $config;
protected LoggerInterface $logger; protected LoggerInterface $logger;
protected NgController $ngControl; protected NgCtl $ngControl;
private IfConfig $ifConfig;
public function __construct( public function __construct(
Config $config, Config $config,
LoggerInterface $logger, LoggerInterface $logger,
NgController $ngControl NgCtl $ngControl,
IfConfig $ifConfig
) { ) {
parent::__construct('monitor'); parent::__construct('monitor');
$this->config = $config; $this->config = $config;
$this->logger = $logger; $this->logger = $logger;
$this->ngControl = $ngControl; $this->ngControl = $ngControl;
$this->ifConfig = $ifConfig;
} }
/** /**
@ -43,6 +47,7 @@ final class Monitor extends Command
$this->logger->info('Stopping 5268AC ping monitor ...'); $this->logger->info('Stopping 5268AC ping monitor ...');
}); });
$failures = 0;
while ($input->isInteractive()) { while ($input->isInteractive()) {
if (!$this->ping()) { if (!$this->ping()) {
if ($this->ngControl->ngIsConnected()) { if ($this->ngControl->ngIsConnected()) {
@ -52,12 +57,38 @@ final class Monitor extends Command
else { else {
$this->logger->info('Everything is going well.'); $this->logger->info('Everything is going well.');
} }
$failures = 0;
} elseif (!$this->ngControl->ngIsConnected()) { } elseif (!$this->ngControl->ngIsConnected()) {
$this->logger->warning('Connection to ' . $this->config->getPingHost() . ' is down, but EAP is not being bridged!'); $this->logger->warning('Connection to ' . $this->config->getPingHost() . ' is down, but EAP is not being bridged!');
$this->ngControl->ngConnect(); $this->ngControl->ngConnect();
} }
else { else {
$this->logger->error('Connection to ' . $this->config->getPingHost() . ' is down, and EAP is not being bridged! We are stuck!'); $failures++;
if ($failures > 10 ){
$this->logger->error('Connection to ' . $this->config->getPingHost() . ' is down, and EAP is bridged! We are stuck!');
}
elseif ($failures > 3) {
$this->logger->error('Things are stuck. Lets trying restarting things.');
$this->ifConfig->stop(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
$this->ngControl->removeNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
sleep(2);
$this->logger->error('Bringing things back up.');
$this->ngControl->createNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface(),
$this->config->getRgEthernetMac()
);
$this->ifConfig->start(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
}
} }
sleep(5); sleep(5);
} }

34
src/Commands/Restart.php Normal file
View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Pfatt\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class Restart extends Command
{
protected static $defaultName = 'restart';
protected static $defaultDescription = 'Fully restart the netgraph connections';
/**
* {@inheritDoc}
*/
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$application = $this->getApplication();
if (!$application) {
return Command::FAILURE;
}
$application->find('shutdown')
->run(new ArrayInput([]), $output);
$application->find('startup')
->run(new ArrayInput([]), $output);
return Command::SUCCESS;
}
}

48
src/Commands/Shutdown.php Normal file
View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Service\Config;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
final class Shutdown extends Command
{
protected static $defaultName = 'shutdown';
protected static $defaultDescription = 'Shutdown netgraph connections';
protected Config $config;
protected LoggerInterface $logger;
protected NgCtl $ngControl;
public function __construct(
Config $config,
LoggerInterface $logger,
NgCtl $ngControl
) {
parent::__construct('startup');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
}
/**
* {@inheritDoc}
*/
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$this->ngControl->removeNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
return Command::SUCCESS;
}
}

View file

@ -5,7 +5,9 @@ declare(strict_types=1);
namespace Pfatt\Commands; namespace Pfatt\Commands;
use Pfatt\Service\Config; use Pfatt\Service\Config;
use Pfatt\Service\NgController; use Pfatt\Service\IfConfig;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -15,20 +17,26 @@ use Symfony\Component\Process\Process;
final class Startup extends Command final class Startup extends Command
{ {
protected static $defaultName = 'startup'; protected static $defaultName = 'startup';
protected static $defaultDescription = 'Setup initial connection'; protected static $defaultDescription = 'Start netgraph connetion';
protected Config $config; protected Config $config;
protected LoggerInterface $logger; protected LoggerInterface $logger;
protected NgController $ngControl; protected NgCtl $ngControl;
private IfConfig $ifConfig;
private KldLoad $kldLoad;
public function __construct( public function __construct(
Config $config, Config $config,
LoggerInterface $logger, LoggerInterface $logger,
NgController $ngControl NgCtl $ngControl,
IfConfig $ifConfig,
KldLoad $kldLoad
) { ) {
parent::__construct('startup'); parent::__construct('startup');
$this->config = $config; $this->config = $config;
$this->logger = $logger; $this->logger = $logger;
$this->ngControl = $ngControl; $this->ngControl = $ngControl;
$this->ifConfig = $ifConfig;
$this->kldLoad = $kldLoad;
} }
/** /**
@ -38,19 +46,15 @@ final class Startup extends Command
InputInterface $input, InputInterface $input,
OutputInterface $output OutputInterface $output
): int { ): int {
switch ($this->getVeriant()) { switch ($this->getVariant()) {
case 'opnsense': case 'opnsense':
$kldload = function (string $mod): Process {
return new Process(['/sbin/kldload', '-nq', $mod]);
};
$this->logger->info('loading netgraph kernel modules...'); $this->logger->info('loading netgraph kernel modules...');
$kldload('netgraph')->mustRun(); $this->kldLoad->execute('netgraph');
$kldload('ng_ether')->mustRun(); $this->kldLoad->execute('ng_ether');
$kldload('ng_etf')->mustRun(); $this->kldLoad->execute('ng_etf');
$kldload('ng_vlan')->mustRun(); $this->kldLoad->execute('ng_vlan');
$kldload('ng_eiface')->mustRun(); $this->kldLoad->execute('ng_eiface');
$kldload('ng_one2many')->mustRun(); $this->kldLoad->execute('ng_one2many');
$this->logger->info('OK!'); $this->logger->info('OK!');
break; break;
@ -60,7 +64,7 @@ final class Startup extends Command
return new Process([ return new Process([
'/usr/local/bin/php', '/usr/local/bin/php',
'-r', '-r',
'"pfSense_ngctl_attach(\'.\', \'' . $interface . '\';"' '"pfSense_ngctl_attach(\'.\', \'' . $interface . '\');"'
]); ]);
}; };
@ -75,13 +79,19 @@ final class Startup extends Command
$this->config->getRgInterface(), $this->config->getRgInterface(),
$this->config->getRgEthernetMac() $this->config->getRgEthernetMac()
); );
$this->ifConfig->start(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
$this->logger->info("ngeth0 should now be available to configure as your pfSense WAN");
$this->logger->info("Done");
return Command::SUCCESS; return Command::SUCCESS;
} }
/** /**
* @return string * @return string
*/ */
private function getVeriant(): string private function getVariant(): string
{ {
// @todo detect the variant to trigger different behaviors. // @todo detect the variant to trigger different behaviors.
return 'opnsense'; return 'opnsense';

View file

@ -9,9 +9,13 @@ use Monolog\Logger;
use Monolog\Handler\StreamHandler; use Monolog\Handler\StreamHandler;
use Pfatt\Commands\GenDuid; use Pfatt\Commands\GenDuid;
use Pfatt\Commands\Monitor; use Pfatt\Commands\Monitor;
use Pfatt\Commands\Restart;
use Pfatt\Commands\Shutdown;
use Pfatt\Commands\Startup; use Pfatt\Commands\Startup;
use Pfatt\Service\Config; use Pfatt\Service\Config;
use Pfatt\Service\NgController; use Pfatt\Service\IfConfig;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
@ -46,26 +50,27 @@ final class PfattKernel
if (!file_exists($file)) { if (!file_exists($file)) {
$containerBuilder = new ContainerBuilder(); $containerBuilder = new ContainerBuilder();
$containerBuilder->register(Config::class, Config::class) $containerBuilder->register(Config::class, Config::class);
->setPublic(true);
// Setup various logging handlers. // Setup various logging handlers.
$containerBuilder->register('syslogger', SyslogHandler::class) $containerBuilder->register('syslogger', SyslogHandler::class)
->setArguments(['pfatt']) ->setArguments(['pfatt']);
->setPublic(true);
$containerBuilder->register(LoggerInterface::class, Logger::class) $containerBuilder->register(LoggerInterface::class, Logger::class)
->setArguments(['pfatt', [new Reference('syslogger')]]) ->setArguments(['pfatt', [new Reference('syslogger')]]);
->setPublic(true);
$containerBuilder->setAlias(Logger::class, LoggerInterface::class); $containerBuilder->setAlias(Logger::class, LoggerInterface::class);
// Utilities. // Utilities.
$containerBuilder->autowire(NgController::class, NgController::class) $containerBuilder->autowire(NgCtl::class, NgCtl::class);
->setPublic(true); $containerBuilder->autowire(KldLoad::class, KldLoad::class);
$containerBuilder->autowire(IfConfig::class, IfConfig::class);
// Register commands. // Register commands.
$containerBuilder->autowire(Startup::class, Startup::class) $containerBuilder->autowire(Startup::class, Startup::class)
->setPublic(true); ->setPublic(true);
$containerBuilder->autowire(Shutdown::class, Shutdown::class)
->setPublic(true);
$containerBuilder->autowire(Restart::class, Restart::class)
->setPublic(true);
$containerBuilder->autowire(GenDuid::class, GenDuid::class) $containerBuilder->autowire(GenDuid::class, GenDuid::class)
->setPublic(true); ->setPublic(true);
$containerBuilder->autowire(Monitor::class, Monitor::class) $containerBuilder->autowire(Monitor::class, Monitor::class)
@ -76,8 +81,7 @@ final class PfattKernel
->setArguments([ ->setArguments([
new Reference('service_container'), new Reference('service_container'),
$this->commands $this->commands
]) ]);
->setPublic(true);
$containerBuilder->autowire(PfattApplication::class, PfattApplication::class) $containerBuilder->autowire(PfattApplication::class, PfattApplication::class)
->addMethodCall('setCommandLoader', [new Reference(ContainerCommandLoader::class)]) ->addMethodCall('setCommandLoader', [new Reference(ContainerCommandLoader::class)])
->setPublic(true); ->setPublic(true);

57
src/Service/IfConfig.php Normal file
View file

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Pfatt\Service;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
class IfConfig
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function start(string $ont, string $rg): void
{
$this->logger->info(" enabling $rg interface...");
$this->exec([$rg, 'up']);
$this->logger->info('OK!');
$this->logger->info(" enabling $ont interface...");
$this->exec([$ont, 'up"']);
$this->logger->info('OK!');
$this->logger->info(" enabling promiscuous mode on $rg...");
$this->exec([$rg, 'promisc']);
$this->logger->info('OK!');
$this->logger->info(" enabling promiscuous mode on $ont...");
$this->exec([$ont, 'promisc']);
$this->logger->info('OK!');
}
public function stop(string $ont, string $rg): void
{
//
}
/**
* Run a ifconfig command.
*
* @param array<int, string> $args
* Additional arguments to pass to ifconfig.
*
* @return bool
* True on success, false on failure.
*/
private function exec(array $args): bool
{
$process = new Process(['/sbin/ifconfig', ...$args], '/tmp');
return !$process->run();
}
}

25
src/Service/KldLoad.php Normal file
View file

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Pfatt\Service;
use Symfony\Component\Process\Process;
class KldLoad
{
/**
* Load a module with kldload.
*
* @param string $module
* Additional arguments to pass to kldload.
*
* @return bool
* True on success, false on failure.
*/
public function execute(string $module): bool
{
$process = new Process(['/sbin/kldload', '-nq', $module], '/tmp');
return !$process->run();
}
}

View file

@ -8,7 +8,7 @@ use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
class NgController implements LoggerAwareInterface class NgCtl implements LoggerAwareInterface
{ {
private LoggerInterface $logger; private LoggerInterface $logger;
@ -22,7 +22,7 @@ class NgController implements LoggerAwareInterface
*/ */
public function ngIsConnected(): bool public function ngIsConnected(): bool
{ {
return $this->ngCtlRun(['show', 'laneapfilter:eapout']); return $this->exec(['show', 'laneapfilter:eapout']);
} }
/** /**
@ -31,7 +31,7 @@ class NgController implements LoggerAwareInterface
public function ngRmHook(): void public function ngRmHook(): void
{ {
$this->logger->info('Disconnecting netgraph node ...'); $this->logger->info('Disconnecting netgraph node ...');
$this->ngCtlRun(['rmhook', 'laneapfilter: eapout']) ? $this->exec(['rmhook', 'laneapfilter:', 'eapout']) ?
$this->logger->info('OK!') : $this->logger->info('OK!') :
$this->logger->error('ERROR!'); $this->logger->error('ERROR!');
} }
@ -42,7 +42,7 @@ class NgController implements LoggerAwareInterface
public function ngConnect(): void public function ngConnect(): void
{ {
$this->logger->info('Connecting netgraph node ...'); $this->logger->info('Connecting netgraph node ...');
$this->ngCtlRun(['connect', 'waneapfilter:', 'laneapfilter:', 'eapout', 'eapout']) ? $this->exec(['connect', 'waneapfilter:', 'laneapfilter:', 'eapout', 'eapout']) ?
$this->logger->info('OK!') : $this->logger->info('OK!') :
$this->logger->error('ERROR!'); $this->logger->error('ERROR!');
} }
@ -63,27 +63,26 @@ class NgController implements LoggerAwareInterface
$this->logger->info('Building netgraph nodes.'); $this->logger->info('Building netgraph nodes.');
$this->logger->info(' creating ng_one2many...'); $this->logger->info(' creating ng_one2many...');
$this->ngCtlRun(['mkpeer', $ont . ':', 'one2many', 'lower', 'one']); $this->exec(['mkpeer', $ont . ':', 'one2many', 'lower', 'one']);
$this->ngCtlRun(['name', $ont . ':lower', 'o2m']); $this->exec(['name', $ont . ':lower', 'o2m']);
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(' creating vlan node and interface...'); $this->logger->info(' creating vlan node and interface...');
$this->ngCtlRun(['mkpeer', 'o2m:', 'vlan', 'many0', ' downstream']); $this->exec(['mkpeer', 'o2m:', 'vlan', 'many0', ' downstream']);
$this->ngCtlRun(['name', 'o2m:many0', 'vlan0']); $this->exec(['name', 'o2m:many0', 'vlan0']);
$this->ngCtlRun(['mkpeer', 'vlan0:', 'eiface', 'vlan0', 'ether']); $this->exec(['mkpeer', 'vlan0:', 'eiface', 'vlan0', 'ether']);
$this->exec([
$this->ngCtlRun([
'msg', 'msg',
'vlan0:', 'vlan0:',
'\'addfilter { vlan=0 hook="vlan0" }\'' '\'addfilter { vlan=0 hook="vlan0" }\''
]); ]);
$this->ngCtlRun(['msg', 'ngeth0:', 'set', $rgMac]); $this->exec(['msg', 'ngeth0:', 'set', $rgMac]);
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" defining etf for $ont (ONT)..."); $this->logger->info(" defining etf for $ont (ONT)...");
$this->ngCtlRun(['mkpeer', 'o2m:', 'etf', 'many1', 'downstream']); $this->exec(['mkpeer', 'o2m:', 'etf', 'many1', 'downstream']);
$this->ngCtlRun(['name', 'o2m:many1', 'waneapfilter']); $this->exec(['name', 'o2m:many1', 'waneapfilter']);
$this->ngCtlRun([ $this->exec([
'connect', 'connect',
'waneapfilter:', 'waneapfilter:',
$ont . ':', $ont . ':',
@ -93,9 +92,9 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" defining etf for $rg (RG)..."); $this->logger->info(" defining etf for $rg (RG)...");
$this->ngCtlRun(['mkpeer', $rg . ':', 'etf', 'lower', 'downstream']); $this->exec(['mkpeer', $rg . ':', 'etf', 'lower', 'downstream']);
$this->ngCtlRun(['name', $rg . ':', 'lower', 'laneapfilter']); $this->exec(['name', $rg . ':', 'lower', 'laneapfilter']);
$this->ngCtlRun([ $this->exec([
'connect', 'connect',
'laneapfilter:', 'laneapfilter:',
$rg . ':', $rg . ':',
@ -105,7 +104,7 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" bridging etf for $ont <-> $rg..."); $this->logger->info(" bridging etf for $ont <-> $rg...");
$this->ngCtlRun([ $this->exec([
'connect', 'connect',
'waneapfilter:', 'waneapfilter:',
'laneapfilter:', 'laneapfilter:',
@ -115,12 +114,12 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" defining filters for EAP traffic..."); $this->logger->info(" defining filters for EAP traffic...");
$this->ngCtlRun([ $this->exec([
'msg', 'msg',
'waneapfilter:', 'waneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\'' '\'setfilter { matchhook="eapout" ethertype=0x888e }\''
]); ]);
$this->ngCtlRun([ $this->exec([
'msg', 'msg',
'laneapfilter:', 'laneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\'' '\'setfilter { matchhook="eapout" ethertype=0x888e }\''
@ -128,7 +127,7 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" enabling one2many links..."); $this->logger->info(" enabling one2many links...");
$this->ngCtlRun([ $this->exec([
'msg', 'msg',
'o2m:', 'o2m:',
'setconfig', 'setconfig',
@ -137,23 +136,19 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!'); $this->logger->info('OK!');
$this->logger->info(" removing waneapfilter:nomatch hook..."); $this->logger->info(" removing waneapfilter:nomatch hook...");
$this->ngCtlRun(['rmhook', 'waneapfilter:', 'nomatch']); $this->exec(['rmhook', 'waneapfilter:', 'nomatch']);
$this->logger->info('OK!'); $this->logger->info('OK!');
}
$this->logger->info(" enabling $rg interface..."); public function removeNodes(string $ont, string $rg): void
$this->ngCtlRun([$rg, 'up']); {
$this->logger->info('OK!'); $this->exec(['shutdown', 'waneapfilter:']);
$this->exec(['shutdown', 'laneapfilter:']);
$this->logger->info(" enabling $ont interface..."); $this->exec(['shutdown', $ont . ':']);
$this->ngCtlRun([$ont, 'up"']); $this->exec(['shutdown', $rg . ':']);
$this->logger->info('OK!'); $this->exec(['shutdown', 'o2m:']);
$this->exec(['shutdown', 'vlan0:']);
$this->logger->info(" enabling promiscuous mode on $rg..."); $this->exec(['shutdown', 'ngeth0:']);
$this->ngCtlRun([$rg, 'promisc']);
$this->logger->info('OK!');
$this->logger->info("ngeth0 should now be available to configure as your pfSense WAN");
$this->logger->info("Done");
} }
/** /**
@ -165,7 +160,7 @@ class NgController implements LoggerAwareInterface
* @return bool * @return bool
* True on success, false on failure. * True on success, false on failure.
*/ */
private function ngCtlRun(array $args): bool private function exec(array $args): bool
{ {
$process = new Process(['/usr/sbin/ngctl', ...$args], '/tmp'); $process = new Process(['/usr/sbin/ngctl', ...$args], '/tmp');
return !$process->run(); return !$process->run();