From a1ec78bf0dc93d0e05e5f066f1949dc3baecea06 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 14:44:51 +0200 Subject: Adding upstream version 0.20.0. Signed-off-by: Daniel Baumann --- vendor/gipfl/icinga-cli-daemon/composer.json | 24 ++ .../src/DbResourceConfigWatch.php | 163 ++++++++++++++ .../icinga-cli-daemon/src/FinishedProcessState.php | 66 ++++++ vendor/gipfl/icinga-cli-daemon/src/IcingaCli.php | 144 ++++++++++++ .../gipfl/icinga-cli-daemon/src/IcingaCliRpc.php | 45 ++++ .../icinga-cli-daemon/src/IcingaCliRunner.php | 88 ++++++++ vendor/gipfl/icinga-cli-daemon/src/RetryUnless.php | 244 +++++++++++++++++++++ .../gipfl/icinga-cli-daemon/src/StateMachine.php | 113 ++++++++++ 8 files changed, 887 insertions(+) create mode 100644 vendor/gipfl/icinga-cli-daemon/composer.json create mode 100644 vendor/gipfl/icinga-cli-daemon/src/DbResourceConfigWatch.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/FinishedProcessState.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/IcingaCli.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/IcingaCliRpc.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/IcingaCliRunner.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/RetryUnless.php create mode 100644 vendor/gipfl/icinga-cli-daemon/src/StateMachine.php (limited to 'vendor/gipfl/icinga-cli-daemon') diff --git a/vendor/gipfl/icinga-cli-daemon/composer.json b/vendor/gipfl/icinga-cli-daemon/composer.json new file mode 100644 index 0000000..ec38ba2 --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/composer.json @@ -0,0 +1,24 @@ +{ + "name": "gipfl/icinga-cli-daemon", + "type": "library", + "description": "Helpers for Icinga CLI Daemons", + "homepage": "https://github.com/gipfl/icinga-cli-daemon", + "config": { + "sort-packages": true, + "platform": { + "php": "5.6.3" + } + }, + "autoload": { + "psr-4": { + "gipfl\\IcingaCliDaemon\\": "src/" + } + }, + "require": { + "php": ">=5.6.3", + "ext-posix": "*", + "gipfl/cli": ">=0.5.0", + "react/event-loop": ">=1.1", + "react/promise": ">=2.7" + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/DbResourceConfigWatch.php b/vendor/gipfl/icinga-cli-daemon/src/DbResourceConfigWatch.php new file mode 100644 index 0000000..08b188f --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/DbResourceConfigWatch.php @@ -0,0 +1,163 @@ +dbResourceName = $dbResourceName; + + return $self; + } + + /** + * @param string $moduleName + * @return DbResourceConfigWatch + */ + public static function module($moduleName) + { + $self = new static(); + $self->configFile = Config::module($moduleName)->getConfigFile(); + $self->resourceConfigFile = Config::app('resources')->getConfigFile(); + + return $self; + } + + /** + * @param int|float $interval + * @return $this + */ + public function setInterval($interval) + { + if (! \is_int($interval) && ! \is_float($interval)) { + throw new InvalidArgumentException( + '$interval needs to be either int or float' + ); + } + $this->interval = $interval; + + return $this; + } + + /** + * @param callable $callable + * @return $this + */ + public function notify($callable) + { + if (! \is_callable($callable)) { + throw new InvalidArgumentException('$callable needs to be callable'); + } + $this->callbacks[] = $callable; + + return $this; + } + + /** + * @param LoopInterface $loop + */ + public function run(LoopInterface $loop) + { + $check = function () { + $this->checkForFreshConfig(); + }; + $loop->addPeriodicTimer($this->interval, $check); + $loop->futureTick($check); + } + + protected function checkForFreshConfig() + { + if ($this->configHasBeenChanged()) { + $this->emitNewConfig($this->resourceConfig); + } + } + + protected function emitNewConfig($config) + { + foreach ($this->callbacks as $callback) { + $callback($config); + } + } + + protected function getResourceName() + { + if ($this->dbResourceName) { + return $this->dbResourceName; + } else { + return $this->loadDbResourceName(); + } + } + + protected function loadDbResourceName() + { + $parsed = @\parse_ini_file($this->configFile, true); + if (isset($parsed['db']['resource'])) { + return $parsed['db']['resource']; + } else { + return null; + } + } + + protected function loadDbConfigFromDisk($name) + { + if ($name === null) { + return null; + } + + $parsed = @\parse_ini_file($this->resourceConfigFile, true); + if (isset($parsed[$name])) { + $section = $parsed[$name]; + \ksort($section); + + return $section; + } else { + return null; + } + } + + protected function configHasBeenChanged() + { + $resource = $this->loadDbConfigFromDisk($this->loadDbResourceName()); + if ($resource !== $this->resourceConfig) { + $this->resourceConfig = $resource; + + return true; + } else { + return false; + } + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/FinishedProcessState.php b/vendor/gipfl/icinga-cli-daemon/src/FinishedProcessState.php new file mode 100644 index 0000000..9ca5e5f --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/FinishedProcessState.php @@ -0,0 +1,66 @@ +exitCode = $exitCode; + $this->termSignal = $termSignal; + } + + public function succeeded() + { + return $this->exitCode === 0; + } + + /** + * @return int|null + */ + public function getExitCode() + { + return $this->exitCode; + } + + public function getTermSignal() + { + return $this->termSignal; + } + + public function getCombinedExitCode() + { + if ($this->exitCode === null) { + if ($this->termSignal === null) { + return 255; + } else { + return 255 + $this->termSignal; + } + } else { + return $this->exitCode; + } + } + + public function getReason() + { + if ($this->exitCode === null) { + if ($this->termSignal === null) { + return 'Process died'; + } else { + return 'Process got terminated with SIGNAL ' . $this->termSignal; + } + } else { + if ($this->exitCode === 0) { + return 'Process finished successfully'; + } else { + return 'Process exited with exit code ' . $this->exitCode; + } + } + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/IcingaCli.php b/vendor/gipfl/icinga-cli-daemon/src/IcingaCli.php new file mode 100644 index 0000000..8aad4c6 --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/IcingaCli.php @@ -0,0 +1,144 @@ +runner = $runner; + $this->init(); + } + + protected function init() + { + // Override this if you want. + } + + public function setArguments($arguments) + { + $this->arguments = $arguments; + + return $this; + } + + public function getArguments() + { + return $this->arguments; + } + + public function run(LoopInterface $loop) + { + $process = $this->runner->command($this->getArguments()); + $canceller = function () use ($process) { + // TODO: first soft, then hard + $process->terminate(); + }; + $deferred = new Deferred($canceller); + $process->on('exit', function ($exitCode, $termSignal) use ($deferred) { + $state = new FinishedProcessState($exitCode, $termSignal); + if ($state->succeeded()) { + $deferred->resolve(); + } else { + $deferred->reject(new Exception($state->getReason())); + } + }); + + $process->start($loop); + if ($this->deferredStdin instanceof Deferred) { + $this->deferredStdin->resolve($process->stdin); + } else { + $this->stdin = $process->stdin; + } + if ($this->deferredStdout instanceof Deferred) { + $this->deferredStdout->resolve($process->stdout); + } else { + $this->stdout = $process->stdout; + } + if ($this->deferredStderr instanceof Deferred) { + $this->deferredStderr->resolve($process->stderr); + } else { + $this->stderr = $process->stderr; + } + $this->emit('start', [$process]); + + return $deferred->promise(); + } + + /** + * @return \React\Stream\WritableStreamInterface + */ + public function stdin() + { + if ($this->stdin === null) { + $this->deferredStdin = new Deferred(); + $this->stdin = Stream\unwrapWritable($this->deferredStdin->promise()); + } + + return $this->stdin; + } + + /** + * @return \React\Stream\ReadableStreamInterface + */ + public function stdout() + { + if ($this->stdout === null) { + $this->deferredStdout = new Deferred(); + $this->stdout = Stream\unwrapReadable($this->deferredStdout->promise()); + } + + return $this->stdout; + } + + /** + * @return \React\Stream\ReadableStreamInterface + */ + public function stderr() + { + if ($this->stderr === null) { + $this->deferredStderr = new Deferred(); + $this->stderr = Stream\unwrapReadable($this->deferredStderr->promise()); + } + + return $this->stderr; + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRpc.php b/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRpc.php new file mode 100644 index 0000000..473d4ed --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRpc.php @@ -0,0 +1,45 @@ +on('start', function (Process $process) { + $netString = new StreamWrapper( + $process->stdout, + $process->stdin + ); + $netString->on('error', function (Exception $e) { + $this->emit('error', [$e]); + }); + $this->rpc()->handle($netString); + }); + } + + /** + * @return Connection + */ + public function rpc() + { + if ($this->rpc === null) { + $this->rpc = new Connection(); + } + + return $this->rpc; + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRunner.php b/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRunner.php new file mode 100644 index 0000000..60a25cc --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/IcingaCliRunner.php @@ -0,0 +1,88 @@ +binary = CliProcess::getBinaryPath(); + $this->cwd = CliProcess::getInitialCwd(); + } else { + $this->binary = $binary; + } + } + + /** + * @param mixed array|...$arguments + * @return Process + */ + public function command($arguments = null) + { + if (! \is_array($arguments)) { + $arguments = \func_get_args(); + } + + return new Process( + $this->escapedCommand($arguments), + $this->cwd, + $this->env + ); + } + + /** + * @param string|null $cwd + */ + public function setCwd($cwd) + { + if ($cwd === null) { + $this->cwd = $cwd; + } else { + $this->cwd = (string) $cwd; + } + } + + /** + * @param array|null $env + */ + public function setEnv($env) + { + if ($env === null) { + $this->env = $env; + } else { + $this->env = (array) $env; + } + } + + /** + * @param $arguments + * @return string + */ + protected function escapedCommand($arguments) + { + $command = ['exec', \escapeshellcmd($this->binary)]; + + foreach ($arguments as $argument) { + if (\ctype_alnum(preg_replace('/^-{1,2}/', '', $argument))) { + $command[] = $argument; + } else { + $command[] = \escapeshellarg($argument); + } + } + + return \implode(' ', $command); + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/RetryUnless.php b/vendor/gipfl/icinga-cli-daemon/src/RetryUnless.php new file mode 100644 index 0000000..0303b2c --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/RetryUnless.php @@ -0,0 +1,244 @@ +callback = $callback; + $this->expectsSuccess = $expectsSuccess; + } + + public static function succeeding($callback) + { + return new static($callback); + } + + public static function failing($callback) + { + return new static($callback, false); + } + + public function run(LoopInterface $loop) + { + $this->assertNotRunning(); + $this->deferred = $deferred = new Deferred(); + $this->loop = $loop; + $loop->futureTick(function () { + $this->nextAttempt(); + }); + + return $deferred->promise(); + } + + public function getLastError() + { + return $this->lastError; + } + + public function setInterval($interval) + { + $this->interval = $interval; + + return $this; + } + + public function slowDownAfter($burst, $interval) + { + $this->burst = $burst; + $this->finalInterval = $interval; + + return $this; + } + + public function pause() + { + $this->removeEventualTimer(); + $this->paused = true; + + return $this; + } + + public function resume() + { + if ($this->paused) { + $this->paused = false; + if ($this->timer === null) { + $this->nextAttempt(); + } + } + } + + public function reset() + { + $this->attempts = 0; + $this->paused = false; + $this->removeEventualTimer(); + $this->rejectEventualDeferred('RetryUnless has been reset'); + + return $this; + } + + public function getAttempts() + { + return $this->attempts; + } + + protected function nextAttempt() + { + if ($this->paused) { + return; + } + + $this->removeEventualTimer(); + $this->attempts++; + try { + $callback = $this->callback; + $this->handleResult($callback()); + } catch (Exception $e) { + $this->handleResult($e); + } + } + + protected function logError(Exception $e) + { + if ($this->lastError !== $e->getMessage()) { + $this->lastError = $e->getMessage(); + Logger::error($e); + } + } + + protected function handleResult($result) + { + if ($this->expectsSuccess) { + if ($result instanceof Exception) { + $this->logError($result); + $this->scheduleNextAttempt(); + } elseif ($result instanceof PromiseInterface) { + $later = function ($result) { + $this->handleResult($result); + }; + $result->then($later, $later); + } else { + $this->succeed($result); + } + } else { + if ($result instanceof Exception) { + $this->succeed($result); + } else { + $this->scheduleNextAttempt(); + } + } + } + + protected function scheduleNextAttempt() + { + if ($this->timer !== null) { + throw new RuntimeException( + 'RetryUnless schedules next attempt while already scheduled' + ); + } + $this->timer = $this->loop->addTimer($this->getNextInterval(), function () { + $this->nextAttempt(); + }); + } + + protected function succeed($result) + { + $this->removeEventualTimer(); + if ($this->deferred === null) { + Logger::warning('RetryUnless tries to resolve twice'); + + return; + } + $this->deferred->resolve($result); + $this->deferred = null; + $this->reset(); + } + + protected function getNextInterval() + { + if ($this->burst === null) { + return $this->interval; + } + + return $this->attempts >= $this->burst + ? $this->finalInterval + : $this->interval; + } + + protected function assertNotRunning() + { + if ($this->deferred) { + throw new RuntimeException( + 'Cannot re-run RetryUnless while already running' + ); + } + } + + protected function removeEventualTimer() + { + if ($this->timer) { + $this->loop->cancelTimer($this->timer); + $this->timer = null; + } + } + + protected function rejectEventualDeferred($reason) + { + if ($this->deferred !== null) { + $deferred = $this->deferred; + $this->deferred = null; + $deferred->reject($reason); + } + } + + public function __destruct() + { + $this->removeEventualTimer(); + $this->rejectEventualDeferred('RetryUnless has been destructed'); + + $this->loop = null; + } +} diff --git a/vendor/gipfl/icinga-cli-daemon/src/StateMachine.php b/vendor/gipfl/icinga-cli-daemon/src/StateMachine.php new file mode 100644 index 0000000..d8ec470 --- /dev/null +++ b/vendor/gipfl/icinga-cli-daemon/src/StateMachine.php @@ -0,0 +1,113 @@ +currentState !== null) { + throw new RuntimeException('StateMachine has already been initialized'); + } + $this->currentState = $initialState; + } + + /** + * @param string|array $fromState + * @param string $toState + * @param callable $callback + * @return $this + */ + public function onTransition($fromState, $toState, $callback) + { + if (is_array($fromState)) { + foreach ($fromState as $state) { + $this->onTransition($state, $toState, $callback); + } + } else { + $this->allowTransition($fromState, $toState); + $this->allowedTransitions[$fromState][$toState][] = $callback; + } + + return $this; + } + + public function allowTransition($fromState, $toState) + { + if (! isset($this->allowedTransitions[$fromState][$toState])) { + $this->allowedTransitions[$fromState][$toState] = []; + } + + return $this; + } + + /** + * @param $state + * @param $callback + * @return $this + */ + public function onState($state, $callback) + { + if (! isset($this->onState[$state])) { + $this->onState[$state] = []; + } + + $this->onState[$state][] = $callback; + + return $this; + } + + public function getState() + { + if ($this->currentState === null) { + throw new RuntimeException('StateMachine has not been initialized'); + } + + return $this->currentState; + } + + public function setState($state) + { + $fromState = $this->getState(); + if ($this->canTransit($fromState, $state)) { + $this->currentState = $state; + $this->runStateTransition($fromState, $state); + } else { + throw new RuntimeException(sprintf( + 'A transition from %s to %s is not allowed', + $fromState, + $state + )); + } + } + + private function runStateTransition($fromState, $toState) + { + if (isset($this->allowedTransitions[$fromState][$toState])) { + foreach ($this->allowedTransitions[$fromState][$toState] as $callback) { + $callback(); + } + } + if (isset($this->onState[$toState])) { + foreach ($this->onState[$toState] as $callback) { + $callback(); + } + } + } + + public function canTransit($fromState, $toState) + { + return isset($this->allowedTransitions[$fromState][$toState]); + } +} -- cgit v1.2.3