Skip to content

Commit

Permalink
Validate the metrics --range against the environment's max_range
Browse files Browse the repository at this point in the history
The --range now supports the "y" and "w" suffixes for years and weeks.
  • Loading branch information
pjcdawkins committed Jan 17, 2024
1 parent f3fb76c commit 26fc25b
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 21 deletions.
8 changes: 4 additions & 4 deletions src/Command/Metrics/AllMetricsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$timeSpec = $this->validateTimeInput($input);
$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

$timeSpec = $this->validateTimeInput($input, $this->getSelectedEnvironment());
if ($timeSpec === false) {
return 1;
}

$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

/** @var \Platformsh\Cli\Service\Table $table */
$table = $this->getService('table');

Expand Down
7 changes: 4 additions & 3 deletions src/Command/Metrics/CpuCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$timeSpec = $this->validateTimeInput($input);
$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

$timeSpec = $this->validateTimeInput($input, $this->getSelectedEnvironment());
if ($timeSpec === false) {
return 1;
}

$this->validateInput($input, false, true);

/** @var \Platformsh\Cli\Service\Table $table */
$table = $this->getService('table');

Expand Down
1 change: 1 addition & 0 deletions src/Command/Metrics/CurlCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ protected function configure()

protected function execute(InputInterface $input, OutputInterface $output)
{
$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

// Initialize the API service so that it gets CommandBase's event listeners
Expand Down
7 changes: 4 additions & 3 deletions src/Command/Metrics/DiskUsageCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$timeSpec = $this->validateTimeInput($input);
$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

$timeSpec = $this->validateTimeInput($input, $this->getSelectedEnvironment());
if ($timeSpec === false) {
return 1;
}
Expand All @@ -66,8 +69,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
$table = $this->getService('table');
$table->removeDeprecatedColumns(['interval'], '', $input, $output);

$this->validateInput($input, false, true);

if (!$table->formatIsMachineReadable()) {
$this->displayEnvironmentHeader();
}
Expand Down
7 changes: 4 additions & 3 deletions src/Command/Metrics/MemCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$timeSpec = $this->validateTimeInput($input);
$this->chooseEnvFilter = $this->filterEnvsByState(['active']);
$this->validateInput($input, false, true);

$timeSpec = $this->validateTimeInput($input, $this->getSelectedEnvironment());
if ($timeSpec === false) {
return 1;
}

$this->validateInput($input, false, true);

/** @var \Platformsh\Cli\Service\Table $table */
$table = $this->getService('table');

Expand Down
47 changes: 39 additions & 8 deletions src/Command/Metrics/MetricsCommandBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ protected function addMetricsOptions()
$duration = new Duration();
$this->addOption('range', 'r', InputOption::VALUE_REQUIRED,
'The time range. Metrics will be loaded for this duration until the end time (--to).'
. "\n" . 'You can specify units: hours (h), minutes (m), or seconds (s).'
. "\n" . 'You can specify units: s (seconds), m (minutes), h (hours), d (days), w (weeks), or y (years).'
. "\n" . \sprintf(
'Minimum <comment>%s</comment>, maximum <comment>8h</comment> or more (depending on the project), default <comment>%s</comment>.',
$duration->humanize(self::MIN_RANGE),
Expand All @@ -123,7 +123,7 @@ protected function addMetricsOptions()
/**
* Returns the metrics URL and collection information for the selected environment.
*
* @return array{'href': string, 'collection': string}|false
* @return array{href: string, collection: string, max_range: string}|false
* The link data or false on failure.
*/
protected function getMetricsLink(Environment $environment)
Expand Down Expand Up @@ -332,10 +332,11 @@ protected function fetchMetrics(InputInterface $input, TimeSpec $timeSpec, Envir
* @see self::startTime, self::$endTime, self::$interval
*
* @param InputInterface $input
* @param Environment $environment
*
* @return TimeSpec|false
*/
protected function validateTimeInput(InputInterface $input)
protected function validateTimeInput(InputInterface $input, Environment $environment)
{
$interval = null;
if ($intervalStr = $input->getOption('interval')) {
Expand All @@ -361,13 +362,24 @@ protected function validateTimeInput(InputInterface $input)
$endTime = time();
}
if ($rangeStr = $input->getOption('range')) {
$rangeSeconds = (new Duration())->toSeconds($rangeStr);
$rangeDuration = $this->parseDuration($rangeStr);
if (!$rangeDuration) {
$this->stdErr->writeln('Invalid --range: <error>' . $rangeStr . '</error>');
return false;
}
$rangeSeconds = $rangeDuration->toSeconds();
if (empty($rangeSeconds)) {
$this->stdErr->writeln('Invalid --range: <error>' . $rangeStr . '</error>');
return false;
} elseif ($rangeSeconds < self::MIN_RANGE) {
$this->stdErr->writeln(\sprintf('The --range <error>%s</error> is too short: it must be at least %d seconds (%s).', $rangeStr, self::MIN_RANGE, (new Duration())->humanize(self::MIN_RANGE)));
return false;
} elseif (($link = $this->getMetricsLink($environment)) && isset($link['max_range'])) {
$maxRange = $this->parseDuration($link['max_range']);
if ($rangeSeconds > $maxRange->toSeconds()) {
$this->stdErr->writeln(\sprintf('The --range <error>%s</error> is too long: the maximum is %s.', $rangeStr, $link['max_range']));
return false;
}
}
$rangeSeconds = \intval($rangeSeconds);
} else {
Expand Down Expand Up @@ -404,10 +416,9 @@ protected function validateTimeInput(InputInterface $input)
*/
private function defaultInterval($range)
{
$divisor = 5; // Number of points per time range.
// Number of seconds to round to:
$granularity = 10;
foreach ([3600*24, 3600*6, 3600*3, 3600, 600, 300, 60, 30] as $level) {
$divisor = 6; // Minimum number of points per time range.
$granularity = 10; // Number of seconds to round to.
foreach ([3600*24*365, 3600*24*90, 3600*24*30, 3600*24*7, 3600*24, 3600*6, 3600*3, 3600, 600, 300, 60, 30] as $level) {
if ($range >= $level * $divisor) {
$granularity = $level;
break;
Expand All @@ -421,6 +432,26 @@ private function defaultInterval($range)
return (int) $interval;
}

/**
* Parses a duration.
*
* Supports 'y' and 'w' in addition to the Duration class's suffixes of
* 'h', 'm', and 'd'.
*
* @param string $duration
* @return Duration|false
*/
private function parseDuration($duration)
{
if (preg_match('/^([0-9.]+)\s*y$/i', $duration, $matches) === 1) {
return new Duration(floatval($matches[1]) * 365.25 * 86400);
}
if (preg_match('/^([0-9.]+)\s*w$/i', $duration, $matches) === 1) {
return new Duration(floatval($matches[1]) * 7 * 86400);
}
return (new Duration())->parse($duration);
}

/**
* Returns the deployment type of an environment (needed for differing queries).
*
Expand Down

0 comments on commit 26fc25b

Please sign in to comment.