-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #164 from scoutapp/additional-core-agent-launch-lo…
…gging Additional core agent launch logging
- Loading branch information
Showing
11 changed files
with
310 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Scoutapm\CoreAgent; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use RuntimeException; | ||
use Throwable; | ||
use function array_map; | ||
use function exec; | ||
use function explode; | ||
use function function_exists; | ||
use function implode; | ||
use function in_array; | ||
use function ini_get; | ||
use function sprintf; | ||
use function stripos; | ||
|
||
/** @internal */ | ||
class Launcher | ||
{ | ||
/** @var LoggerInterface */ | ||
private $logger; | ||
/** @var string */ | ||
private $coreAgentSocketPath; | ||
/** @var string|null */ | ||
private $coreAgentLogLevel; | ||
/** @var string */ | ||
private $coreAgentLogFile; | ||
/** @var string|null */ | ||
private $coreAgentConfigFile; | ||
|
||
public function __construct( | ||
LoggerInterface $logger, | ||
string $coreAgentSocketPath, | ||
?string $coreAgentLogLevel, | ||
?string $coreAgentLogFile, | ||
?string $coreAgentConfigFile | ||
) { | ||
$this->logger = $logger; | ||
$this->coreAgentSocketPath = $coreAgentSocketPath; | ||
$this->coreAgentLogLevel = $coreAgentLogLevel; | ||
$this->coreAgentConfigFile = $coreAgentConfigFile; | ||
$this->coreAgentLogFile = $coreAgentLogFile ?? '/dev/null'; | ||
} | ||
|
||
public function launch(string $coreAgentBinaryPath) : bool | ||
{ | ||
if (! $this->phpCanExec()) { | ||
return false; | ||
} | ||
|
||
$this->logger->debug('Core Agent Launch in Progress'); | ||
try { | ||
$commandParts = [ | ||
$coreAgentBinaryPath, | ||
'start', | ||
'--daemonize', | ||
'true', | ||
'--log-file', | ||
$this->coreAgentLogFile, | ||
]; | ||
|
||
if ($this->coreAgentLogLevel !== null) { | ||
$commandParts[] = '--log-level'; | ||
$commandParts[] = $this->coreAgentLogLevel; | ||
} | ||
|
||
if ($this->coreAgentConfigFile !== null) { | ||
$commandParts[] = '--config-file'; | ||
$commandParts[] = $this->coreAgentConfigFile; | ||
} | ||
|
||
$commandParts[] = '--socket'; | ||
$commandParts[] = $this->coreAgentSocketPath; | ||
|
||
$escapedCommand = implode(' ', array_map('escapeshellarg', $commandParts)); | ||
|
||
$this->logger->debug(sprintf('Launching core agent with command: %s', $escapedCommand)); | ||
|
||
exec($escapedCommand . ' 2>&1', $output, $exitStatus); | ||
|
||
$this->assertOutputDoesNotContainErrors(implode("\n", $output), $exitStatus); | ||
|
||
return true; | ||
} catch (Throwable $e) { | ||
$this->logger->debug( | ||
sprintf('Failed to launch core agent - exception %s', $e->getMessage()), | ||
['exception' => $e] | ||
); | ||
|
||
return false; | ||
} | ||
} | ||
|
||
private function phpCanExec() : bool | ||
{ | ||
if (! function_exists('exec')) { | ||
$this->logger->warning('PHP function exec is not available'); | ||
|
||
return false; | ||
} | ||
|
||
if (in_array('exec', array_map('trim', explode(',', ini_get('disable_functions'))))) { | ||
$this->logger->warning('PHP function exec is in disabled_functions'); | ||
|
||
return false; | ||
} | ||
|
||
if (exec('echo scoutapm') !== 'scoutapm') { | ||
$this->logger->warning('PHP function exec did not return expected value'); | ||
|
||
return false; | ||
} | ||
|
||
$this->logger->debug('exec is available'); | ||
|
||
return true; | ||
} | ||
|
||
private function assertOutputDoesNotContainErrors(string $output, int $exitStatus) : void | ||
{ | ||
if (stripos($output, "version `GLIBC_2.18' not found") !== false) { | ||
throw new RuntimeException('core-agent currently needs at least glibc 2.18. Output: ' . $output); | ||
} | ||
|
||
if ($exitStatus !== 0) { | ||
throw new RuntimeException('core-agent exited with non-zero status. Output: ' . $output); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Scoutapm\CoreAgent; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use function hash_equals; | ||
use function hash_file; | ||
|
||
/** @internal */ | ||
class Verifier | ||
{ | ||
/** @var LoggerInterface */ | ||
private $logger; | ||
|
||
/** @var string */ | ||
private $coreAgentDownloadPath; | ||
|
||
public function __construct(LoggerInterface $logger, string $coreAgentDownloadPath) | ||
{ | ||
$this->logger = $logger; | ||
$this->coreAgentDownloadPath = $coreAgentDownloadPath; | ||
} | ||
|
||
public function verify() : ?string | ||
{ | ||
// Check for a well formed manifest | ||
$manifest = new Manifest($this->coreAgentDownloadPath . '/manifest.json', $this->logger); | ||
if (! $manifest->isValid()) { | ||
$this->logger->debug('Core Agent verification failed: Manifest is not valid.'); | ||
|
||
return null; | ||
} | ||
|
||
// Check that the hash matches | ||
$binPath = $this->coreAgentDownloadPath . '/' . $manifest->binaryName(); | ||
if (hash_equals($manifest->hashOfBinary(), hash_file('sha256', $binPath))) { | ||
return $binPath; | ||
} | ||
|
||
$this->logger->debug('Core Agent verification failed: SHA mismatch.'); | ||
|
||
return null; | ||
} | ||
} |
Oops, something went wrong.