mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
Fix dsstats partition dispatch and profile retention fallbacks (#8304)
* fix(core): preserve dsstats type and render retention fallbacks Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(auth): use certificate expiry truth in rendering assertions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
This commit is contained in:
1 parent
af9d1591a3
commit
76579e6292
10 files changed
+97
-1
No files matched your search
@@ -213,6 +213,7 @@ function color_import_processor(array &$colors) : array {
|
|||||||
switch ($line_item) {
|
switch ($line_item) {
|
||||||
case 'hex':
|
case 'hex':
|
||||||
$hexcol = $j;
|
$hexcol = $j;
|
||||||
|
// Fall through: retain the hex column alongside the name column.
|
||||||
case 'name':
|
case 'name':
|
||||||
if (!$first_column) {
|
if (!$first_column) {
|
||||||
$save_order .= ', ';
|
$save_order .= ', ';
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ switch (grv('action')) {
|
|||||||
case 'runall':
|
case 'runall':
|
||||||
debug_runall_filtered();
|
debug_runall_filtered();
|
||||||
|
|
||||||
|
// Fall through: render the refreshed list after running the selected sources.
|
||||||
default:
|
default:
|
||||||
$refresh = [
|
$refresh = [
|
||||||
'seconds' => grv('refresh'),
|
'seconds' => grv('refresh'),
|
||||||
|
|||||||
@@ -1141,7 +1141,8 @@ function profile_edit() : void {
|
|||||||
form_selectable_cell(filter_value($rra['name'], '', $url), $i);
|
form_selectable_cell(filter_value($rra['name'], '', $url), $i);
|
||||||
|
|
||||||
form_selectable_cell('<em>' . get_span($profile['step'] * $rra['steps'] * $rra['rows']) . '</em>', $i);
|
form_selectable_cell('<em>' . get_span($profile['step'] * $rra['steps'] * $rra['rows']) . '</em>', $i);
|
||||||
form_selectable_cell('<em>' . isset($timespans[$rra['timespan']]) ? $timespans[$rra['timespan']] : get_span($rra['timespan']) . '</em>', $i); // @phpstan-ignore-line
|
$retention = $timespans[$rra['timespan']] ?? get_span($rra['timespan']);
|
||||||
|
form_selectable_cell('<em>' . $retention . '</em>', $i);
|
||||||
form_selectable_cell('<em>' . $rra['steps'] . '</em>', $i);
|
form_selectable_cell('<em>' . $rra['steps'] . '</em>', $i);
|
||||||
form_selectable_cell('<em>' . $rra['rows'] . '</em>', $i);
|
form_selectable_cell('<em>' . $rra['rows'] . '</em>', $i);
|
||||||
|
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ switch (grv('action')) {
|
|||||||
case 'unlock':
|
case 'unlock':
|
||||||
$_SESSION['sess_graph_lock_id'] = gfrv('id');
|
$_SESSION['sess_graph_lock_id'] = gfrv('id');
|
||||||
$_SESSION['sess_graph_locked'] = (grv('action') == 'lock' ? true : false);
|
$_SESSION['sess_graph_locked'] = (grv('action') == 'lock' ? true : false);
|
||||||
|
// Fall through: show the editor with the new lock state.
|
||||||
case 'graph_edit':
|
case 'graph_edit':
|
||||||
top_header();
|
top_header();
|
||||||
graph_edit();
|
graph_edit();
|
||||||
|
|||||||
@@ -1290,6 +1290,7 @@ function aggregate_create_update(int &$local_graph_id, array $member_graphs, arr
|
|||||||
(local_graph_id, graph_type_id, consolidation_function_id, text_format, value, hard_return, gprint_id, sequence)
|
(local_graph_id, graph_type_id, consolidation_function_id, text_format, value, hard_return, gprint_id, sequence)
|
||||||
VALUES (?, 1, ?, '', '', 'on', 2, ?)", [$local_graph_id, $cf_id, $next_item_sequence++]);
|
VALUES (?, 1, ?, '', '', 'on', 2, ?)", [$local_graph_id, $cf_id, $next_item_sequence++]);
|
||||||
|
|
||||||
|
// Fall through: all totals also need the common totalling graph items.
|
||||||
case AGGREGATE_TOTAL_ONLY:
|
case AGGREGATE_TOTAL_ONLY:
|
||||||
// use the prefix for totalling GPRINTs as given by the user
|
// use the prefix for totalling GPRINTs as given by the user
|
||||||
switch ($_total_type) {
|
switch ($_total_type) {
|
||||||
|
|||||||
@@ -2200,8 +2200,10 @@ function memory_bytes(mixed $val) : mixed {
|
|||||||
switch($last) {
|
switch($last) {
|
||||||
case 'g':
|
case 'g':
|
||||||
$val *= 1024;
|
$val *= 1024;
|
||||||
|
// Fall through: gigabytes also need the megabyte and kilobyte multipliers.
|
||||||
case 'm':
|
case 'm':
|
||||||
$val *= 1024;
|
$val *= 1024;
|
||||||
|
// Fall through: megabytes also need the kilobyte multiplier.
|
||||||
case 'k':
|
case 'k':
|
||||||
$val *= 1024;
|
$val *= 1024;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ if (cacti_sizeof($parms)) {
|
|||||||
case '--partition':
|
case '--partition':
|
||||||
$fpartition = true;
|
$fpartition = true;
|
||||||
|
|
||||||
|
// Preserve the legacy --partition=TYPE spelling for QA callers.
|
||||||
|
if ($value !== '') {
|
||||||
|
$type = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case '--type':
|
case '--type':
|
||||||
$type = $value;
|
$type = $value;
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ switch(grv('action')) {
|
|||||||
|
|
||||||
rrdcheck_purge();
|
rrdcheck_purge();
|
||||||
|
|
||||||
|
// Fall through: display the remaining problems after purging.
|
||||||
default:
|
default:
|
||||||
rrdcheck_display_problems();
|
rrdcheck_display_problems();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
// Copyright (C) 2004-2026 The Cacti Group. GPL-2.0-or-later.
|
||||||
|
|
||||||
|
test('dsstats partition options retain the selected collector type', function (array $parameters, string $expectedType, bool $expectedPartition) {
|
||||||
|
$source = file_get_contents(dirname(__DIR__, 4) . '/poller_dsstats.php');
|
||||||
|
$parser = (new \PhpParser\ParserFactory())->createForNewestSupportedVersion();
|
||||||
|
$nodes = $parser->parse($source);
|
||||||
|
$block = (new \PhpParser\NodeFinder())->findFirst($nodes, static function ($node) {
|
||||||
|
return $node instanceof \PhpParser\Node\Stmt\If_ &&
|
||||||
|
$node->cond instanceof \PhpParser\Node\Expr\FuncCall &&
|
||||||
|
$node->cond->name instanceof \PhpParser\Node\Name &&
|
||||||
|
$node->cond->name->toString() === 'cacti_sizeof' &&
|
||||||
|
$node->cond->args[0]->value instanceof \PhpParser\Node\Expr\Variable &&
|
||||||
|
$node->cond->args[0]->value->name === 'parms';
|
||||||
|
});
|
||||||
|
expect($block)->not->toBeNull();
|
||||||
|
$fragment = substr($source, $block->getStartFilePos(), $block->getEndFilePos() - $block->getStartFilePos() + 1);
|
||||||
|
|
||||||
|
// Execute the actual repository argument parser, before DB/poller work.
|
||||||
|
$parse = static function (array $parms) use ($fragment) : array {
|
||||||
|
$debug = false;
|
||||||
|
$force = false;
|
||||||
|
$fpartition = false;
|
||||||
|
$type = 'pmaster';
|
||||||
|
$thread_id = 0;
|
||||||
|
eval($fragment);
|
||||||
|
|
||||||
|
return [$type, $fpartition];
|
||||||
|
};
|
||||||
|
|
||||||
|
expect($parse($parameters))->toBe([$expectedType, $expectedPartition]);
|
||||||
|
})->with([
|
||||||
|
'no partition request' => [[], 'pmaster', false],
|
||||||
|
'bare long option' => [['--partition'], 'pmaster', true],
|
||||||
|
'bare short option' => [['-p'], 'pmaster', true],
|
||||||
|
'type before partition' => [['--type=bmaster', '--partition'], 'bmaster', true],
|
||||||
|
'type after partition' => [['--partition', '--type=dmaster'], 'dmaster', true],
|
||||||
|
'legacy partition type' => [['--partition=bmaster'], 'bmaster', true],
|
||||||
|
'legacy short partition type' => [['-p=dmaster'], 'dmaster', true],
|
||||||
|
]);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
// Copyright (C) 2004-2026 The Cacti Group. GPL-2.0-or-later.
|
||||||
|
|
||||||
|
test('profile retention labels choose the configured or computed span and retain emphasis', function (?string $configuredLabel) {
|
||||||
|
$source = file_get_contents(dirname(__DIR__, 4) . '/data_source_profiles.php');
|
||||||
|
$parser = (new \PhpParser\ParserFactory())->createForNewestSupportedVersion();
|
||||||
|
$nodes = $parser->parse($source);
|
||||||
|
$finder = new \PhpParser\NodeFinder();
|
||||||
|
$printer = new \PhpParser\PrettyPrinter\Standard();
|
||||||
|
$spanFunction = $finder->findFirst($nodes, static fn ($node) => $node instanceof \PhpParser\Node\Stmt\Function_ && $node->name->toString() === 'get_span');
|
||||||
|
expect($spanFunction)->not->toBeNull();
|
||||||
|
// Bind the actual page-local get_span body as a closure; never shadow core functions.
|
||||||
|
$spanNode = new \PhpParser\Node\Expr\Closure([
|
||||||
|
'params' => $spanFunction->params, 'stmts' => $spanFunction->stmts,
|
||||||
|
'returnType' => $spanFunction->returnType,
|
||||||
|
]);
|
||||||
|
$span = eval('return ' . $printer->prettyPrintExpr($spanNode) . ';');
|
||||||
|
$assignment = $finder->findFirst($nodes, static fn ($node) => $node instanceof \PhpParser\Node\Expr\Assign &&
|
||||||
|
$node->var instanceof \PhpParser\Node\Expr\Variable && $node->var->name === 'retention');
|
||||||
|
$call = $finder->findFirst($nodes, static function ($node) use ($printer) {
|
||||||
|
return $node instanceof \PhpParser\Node\Expr\FuncCall &&
|
||||||
|
$node->name instanceof \PhpParser\Node\Name &&
|
||||||
|
$node->name->toString() === 'form_selectable_cell' &&
|
||||||
|
preg_match('/\$(timespans|retention)\b/', $printer->prettyPrintExpr($node->args[0]->value));
|
||||||
|
});
|
||||||
|
expect($call)->not->toBeNull();
|
||||||
|
|
||||||
|
// Route only the page-local dependency to its production closure.
|
||||||
|
foreach ($finder->findInstanceOf($nodes, \PhpParser\Node\Expr\FuncCall::class) as $dependency) {
|
||||||
|
if ($dependency->name instanceof \PhpParser\Node\Name && $dependency->name->toString() === 'get_span') {
|
||||||
|
$dependency->name = new \PhpParser\Node\Expr\Variable('span');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rra = ['timespan' => 7200];
|
||||||
|
$timespans = $configuredLabel === null ? [] : [7200 => $configuredLabel];
|
||||||
|
|
||||||
|
if ($assignment !== null) {
|
||||||
|
eval($printer->prettyPrintExpr($assignment) . ';');
|
||||||
|
}
|
||||||
|
$result = eval('return ' . $printer->prettyPrintExpr($call->args[0]->value) . ';');
|
||||||
|
expect($result)->toBe('<em>' . ($configuredLabel ?? '2 Hours') . '</em>');
|
||||||
|
})->with(['configured span' => ['Configured span'], 'computed span' => [null]]);
|
||||||
Reference in new issue
Block a user