diff options
| author | Daniel Weipert <code@drogueronin.de> | 2021-04-20 12:45:44 +0200 | 
|---|---|---|
| committer | Daniel Weipert <code@drogueronin.de> | 2021-04-20 12:45:44 +0200 | 
| commit | f7fc6fd54a5f750de8144b9b05d5ac173470c70a (patch) | |
| tree | 8796fc49df1d9d80c7b8817a54580c98c2f100f5 | |
| parent | 3983548e7c0f107fa7b7cc3c4c36aa009590b481 (diff) | |
Adds Connection wrapper for SSH2
| -rw-r--r-- | composer.lock | 152 | ||||
| -rw-r--r-- | src/Command/RunCommand.php | 29 | ||||
| -rw-r--r-- | src/Connection.php | 78 | ||||
| -rw-r--r-- | src/Module/Module.php | 14 | ||||
| -rw-r--r-- | src/Module/State.php | 2 | ||||
| -rw-r--r-- | src/Support/SingletonTraitWithArguments.php | 25 | 
6 files changed, 248 insertions, 52 deletions
diff --git a/composer.lock b/composer.lock index d26cd7d..6f79623 100644 --- a/composer.lock +++ b/composer.lock @@ -177,7 +177,8 @@                  "reference": "d4d5ae3bb6566311b2d42cf888e463b62f6cf0dc"              },              "require": { -                "php": "^8.0" +                "php": "^8.0", +                "twig/twig": "^3.0"              },              "require-dev": {                  "php-iac/php-iac": "*" @@ -561,12 +562,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-ctype.git", -                "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" +                "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", -                "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", +                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", +                "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",                  "shasum": ""              },              "require": { @@ -579,7 +580,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -617,7 +618,7 @@                  "portable"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-ctype/tree/main"              },              "funding": [                  { @@ -633,7 +634,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-07T16:49:33+00:00" +            "time": "2021-02-19T12:13:01+00:00"          },          {              "name": "symfony/polyfill-intl-grapheme", @@ -641,12 +642,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-intl-grapheme.git", -                "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" +                "reference": "053f7184175d5417c933817341c5cc0053ddacd5"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", -                "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", +                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/053f7184175d5417c933817341c5cc0053ddacd5", +                "reference": "053f7184175d5417c933817341c5cc0053ddacd5",                  "shasum": ""              },              "require": { @@ -659,7 +660,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -699,7 +700,7 @@                  "shim"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/main"              },              "funding": [                  { @@ -715,7 +716,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-22T09:19:47+00:00" +            "time": "2021-02-19T12:13:01+00:00"          },          {              "name": "symfony/polyfill-intl-normalizer", @@ -723,12 +724,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-intl-normalizer.git", -                "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" +                "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", -                "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", +                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", +                "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",                  "shasum": ""              },              "require": { @@ -741,7 +742,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -784,7 +785,7 @@                  "shim"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/main"              },              "funding": [                  { @@ -800,7 +801,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-22T09:19:47+00:00" +            "time": "2021-02-19T12:13:01+00:00"          },          {              "name": "symfony/polyfill-mbstring", @@ -808,12 +809,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-mbstring.git", -                "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" +                "reference": "298b87cbbe99cb2c9f88fb1d1de78833b64b483e"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", -                "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", +                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/298b87cbbe99cb2c9f88fb1d1de78833b64b483e", +                "reference": "298b87cbbe99cb2c9f88fb1d1de78833b64b483e",                  "shasum": ""              },              "require": { @@ -826,7 +827,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -865,7 +866,7 @@                  "shim"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-mbstring/tree/main"              },              "funding": [                  { @@ -881,7 +882,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-22T09:19:47+00:00" +            "time": "2021-04-19T09:32:22+00:00"          },          {              "name": "symfony/polyfill-php73", @@ -889,12 +890,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-php73.git", -                "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" +                "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", -                "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", +                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", +                "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010",                  "shasum": ""              },              "require": { @@ -904,7 +905,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -945,7 +946,7 @@                  "shim"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-php73/tree/main"              },              "funding": [                  { @@ -961,7 +962,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-07T16:49:33+00:00" +            "time": "2021-02-19T12:13:01+00:00"          },          {              "name": "symfony/polyfill-php80", @@ -969,12 +970,12 @@              "source": {                  "type": "git",                  "url": "https://github.com/symfony/polyfill-php80.git", -                "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" +                "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0"              },              "dist": {                  "type": "zip", -                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", -                "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", +                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", +                "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0",                  "shasum": ""              },              "require": { @@ -984,7 +985,7 @@              "type": "library",              "extra": {                  "branch-alias": { -                    "dev-main": "1.22-dev" +                    "dev-main": "1.23-dev"                  },                  "thanks": {                      "name": "symfony/polyfill", @@ -1029,7 +1030,7 @@                  "shim"              ],              "support": { -                "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" +                "source": "https://github.com/symfony/polyfill-php80/tree/main"              },              "funding": [                  { @@ -1045,7 +1046,7 @@                      "type": "tidelift"                  }              ], -            "time": "2021-01-07T16:49:33+00:00" +            "time": "2021-02-19T12:13:01+00:00"          },          {              "name": "symfony/service-contracts", @@ -1210,6 +1211,83 @@                  }              ],              "time": "2021-03-17T17:12:23+00:00" +        }, +        { +            "name": "twig/twig", +            "version": "3.x-dev", +            "source": { +                "type": "git", +                "url": "https://github.com/twigphp/Twig.git", +                "reference": "32d72de1885889452f3d8aa298a90b04d263651b" +            }, +            "dist": { +                "type": "zip", +                "url": "https://api.github.com/repos/twigphp/Twig/zipball/32d72de1885889452f3d8aa298a90b04d263651b", +                "reference": "32d72de1885889452f3d8aa298a90b04d263651b", +                "shasum": "" +            }, +            "require": { +                "php": ">=7.2.5", +                "symfony/polyfill-ctype": "^1.8", +                "symfony/polyfill-mbstring": "^1.3" +            }, +            "require-dev": { +                "psr/container": "^1.0", +                "symfony/phpunit-bridge": "^4.4.9|^5.0.9" +            }, +            "default-branch": true, +            "type": "library", +            "extra": { +                "branch-alias": { +                    "dev-master": "3.3-dev" +                } +            }, +            "autoload": { +                "psr-4": { +                    "Twig\\": "src/" +                } +            }, +            "notification-url": "https://packagist.org/downloads/", +            "license": [ +                "BSD-3-Clause" +            ], +            "authors": [ +                { +                    "name": "Fabien Potencier", +                    "email": "fabien@symfony.com", +                    "homepage": "http://fabien.potencier.org", +                    "role": "Lead Developer" +                }, +                { +                    "name": "Twig Team", +                    "role": "Contributors" +                }, +                { +                    "name": "Armin Ronacher", +                    "email": "armin.ronacher@active-4.com", +                    "role": "Project Founder" +                } +            ], +            "description": "Twig, the flexible, fast, and secure template language for PHP", +            "homepage": "https://twig.symfony.com", +            "keywords": [ +                "templating" +            ], +            "support": { +                "issues": "https://github.com/twigphp/Twig/issues", +                "source": "https://github.com/twigphp/Twig/tree/3.x" +            }, +            "funding": [ +                { +                    "url": "https://github.com/fabpot", +                    "type": "github" +                }, +                { +                    "url": "https://tidelift.com/funding/github/packagist/twig/twig", +                    "type": "tidelift" +                } +            ], +            "time": "2021-04-15T10:09:30+00:00"          }      ],      "packages-dev": [], 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 @@ +<?php + +namespace PHPIAC; + +use PHPIAC\Support\SingletonTraitWithArguments; +use phpseclib3\Crypt\PublicKeyLoader; +use phpseclib3\Net\SFTP; +use phpseclib3\Net\SSH2; + +/** + * Class Connection + * + * @method static string exec(string $command, callback $callback = null) + * @method static string|bool|null read(string $expect = '', int $read = 1) + * @method static enablePty() + * @method static disablePty() + */ +class Connection +{ +    use SingletonTraitWithArguments; + +    private SSH2 $ssh; +    private SFTP $sftp; + +    /** +     * Connection constructor. +     * +     * @param string $host +     * @param string $user +     * @param string $key +     * +     * @throws \Exception +     */ +    public function __construct(string $host, string $user, string $key) +    { +        $this->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 @@ +<?php + +namespace PHPIAC\Support; + +use PetrKnap\Php\Singleton\SingletonTrait; + +trait SingletonTraitWithArguments +{ +    use SingletonTrait; + +    /** +     * @param mixed ...$arguments +     * +     * @return self +     */ +    public static function getInstance(mixed ...$arguments) +    { +        $self = get_called_class(); +        if (! isset(self::$instances[$self])) { +            self::$instances[$self] = new $self(...$arguments); +        } + +        return self::$instances[$self]; +    } +}  | 
