From f7fc6fd54a5f750de8144b9b05d5ac173470c70a Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Tue, 20 Apr 2021 12:45:44 +0200 Subject: Adds Connection wrapper for SSH2 --- src/Command/RunCommand.php | 29 +++++------ src/Connection.php | 78 +++++++++++++++++++++++++++++ src/Module/Module.php | 14 +++++- src/Module/State.php | 2 + src/Support/SingletonTraitWithArguments.php | 25 +++++++++ 5 files changed, 133 insertions(+), 15 deletions(-) create mode 100644 src/Connection.php create mode 100644 src/Support/SingletonTraitWithArguments.php (limited to 'src') diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 6d8d2c9..cc9c7fd 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -2,9 +2,8 @@ namespace PHPIAC\Command; +use PHPIAC\Connection; use PHPIAC\Task; -use phpseclib3\Crypt\PublicKeyLoader; -use phpseclib3\Net\SSH2; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -14,36 +13,38 @@ class RunCommand extends Command { protected static $defaultName = 'run'; + /** + * @inheritDoc + */ protected function configure() { $this->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to config file', getcwd() . '/config.php'); } + /** + * @inheritDoc + */ protected function execute(InputInterface $input, OutputInterface $output): int { $config = include $input->getOption('config'); - global $ssh; - $ssh = new SSH2($config['host']); - if (! $ssh->login($config['user'], PublicKeyLoader::load(file_get_contents($config['private_key_file'])))) { - throw new \Exception('Login failed'); - } + Connection::getInstance($config['host'], $config['user'], $config['private_key_file']); - $commands = []; foreach ($config['tasks'] as $task) { /**@var Task $task*/ + if (! $task->module->checkState()) { - $output->writeln($task->getName() . ': Adding commands from ' . get_class($task->module)); - array_push($commands, ...$task->module->getCommands()); + $output->writeln($task->getName()); + $output->writeln('Running'); + + $task->module->getCommands(); } else { - $output->writeln($task->getName() . ': Skipping commands from ' . get_class($task->module)); + $output->writeln($task->getName()); + $output->writeln('Skipping'); } } - // run commands in single exec call - $ssh->exec(implode(PHP_EOL, $commands)); - return Command::SUCCESS; } } diff --git a/src/Connection.php b/src/Connection.php new file mode 100644 index 0000000..2052cd1 --- /dev/null +++ b/src/Connection.php @@ -0,0 +1,78 @@ +ssh = new SSH2($host); + $key = PublicKeyLoader::load(file_get_contents($key)); + if (! $this->ssh->login($user, $key)) { + throw new \Exception('SSH Login failed'); + } + + $this->sftp = new SFTP($host); + if (! $this->sftp->login($user, $key)) { + throw new \Exception('SFTP Login failed'); + } + } + + /** + * Calls SSH2 methods statically + * + * @param string $name + * @param array $arguments + * + * @return mixed + */ + public static function __callStatic(string $name, array $arguments): mixed + { + $self = self::getInstance(); + + if (! method_exists($self->ssh, $name)) { + return $self->sftp->$name(...$arguments); + } + + return $self->ssh->$name(...$arguments); + } + + /** + * @see SFTP::put + */ + public static function put($remote_file, $data, $mode = SFTP::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null): bool + { + $tmp = bin2hex(random_bytes(10)); # work around sftp sudo put restrictions + + return + self::getInstance()->sftp->put("/tmp/$tmp", $data, $mode, $start, $local_start, $progressCallback) && + self::getInstance()->ssh->exec("sudo mv /tmp/$tmp $remote_file"); + } +} diff --git a/src/Module/Module.php b/src/Module/Module.php index 51672f9..48ba5f9 100644 --- a/src/Module/Module.php +++ b/src/Module/Module.php @@ -3,4 +3,16 @@ namespace PHPIAC\Module; abstract class Module implements ModuleInterface -{} +{ + /** + * Module constructor. + * + * @param array $config + */ + public function __construct(array $config) + { + foreach ($config as $key => $value) { + $this->$key = $value; + } + } +} diff --git a/src/Module/State.php b/src/Module/State.php index c7f7af9..040b91e 100644 --- a/src/Module/State.php +++ b/src/Module/State.php @@ -6,4 +6,6 @@ class State { public const PRESENT = 'present'; public const ABSENT = 'absent'; + public const ENABLED = 'enabled'; + public const DISABLED = 'disabled'; } diff --git a/src/Support/SingletonTraitWithArguments.php b/src/Support/SingletonTraitWithArguments.php new file mode 100644 index 0000000..2ac0653 --- /dev/null +++ b/src/Support/SingletonTraitWithArguments.php @@ -0,0 +1,25 @@ +